Logo OnlineCBT
PYTHON Tutorial
PYTHON · LESSON 56

Automation with Files, Spreadsheets and Email

Automate practical office workflows with safe repeatable scripts.

Level: Beginner to Advanced
Duration: ~60 Mins Deep-Dive
Updated: 26 Jul 2026

Lesson 56: Automation with Files, Spreadsheets and Email

1. Introduction to Enterprise Robotic Process Automation (RPA)

In Lesson 55, we mastered web scraping and responsible data harvesting from unstructured HTML web pages. However, once data is extracted or ingested into enterprise systems, software operations require distributing reports, organizing local file archives, generating spreadsheet summaries, and dispatching automated email notifications to business stakeholders.

In modern enterprise software engineering, manual office tasks—such as copying quarterly financial files, formatting Excel workbooks, or sending individual PDF report emails—consume thousands of human hours annually. Python serves as the premier programming language for Robotic Process Automation (RPA), allowing developers to construct automated scripts that orchestrate file systems, spreadsheet workbooks, and email infrastructure effortlessly.

In this lesson, we will explore high-level File System Automation using `shutil` and `pathlib`, master programmatic Excel spreadsheet manipulation using `openpyxl`, construct secure MIME email notification pipelines using Python's standard `smtplib` and `email.message` modules, build end-to-end office workflow automation pipelines, and dispatch automation jobs using Structural Pattern Matching (`match-case`).


2. Advanced File System Automation: `pathlib` & `shutil`

In earlier lessons, we used pathlib.Path for basic file path manipulation. For advanced office file system automation (copying entire directory trees, moving files into dated archives, or compressing folders into ZIP archives), Python provides the high-level `shutil` (Shell Utilities) standard library module.

1. Core File System Operations Summary

  • Copy Individual File
  • shutil.copy(src, dst)
  • Copies file content and permissions from src path to dst path.
  • Copy Directory Tree
  • shutil.copytree(src, dst)
  • Recursively copies an entire directory structure and all nested files.
  • Move / Rename
  • shutil.move(src, dst)
  • Moves or renames a file or directory safely across file systems.
  • Remove Directory
  • shutil.rmtree(path)
  • Recursively deletes a directory tree and all its contents permanently!
  • Archive / Compress
  • shutil.make_archive(base_name, 'zip', root_dir)
  • Compresses a target folder directory into a .zip or .tar.gz archive file.
Automation Goal Python Function Call Operation Description
FILE_SYSTEM_AUTOMATION_DEMO.PY
import shutil
from pathlib import Path

def automate_file_archiving(source_folder: Path, archive_folder: Path) -> Path | None:
    """
    Automates scanning files, categorizing into target subdirectories,
    and compressing completed archives into a ZIP file.
    """
    if not source_folder.exists():
        print(f"[ERROR] Source directory '{source_folder}' does not exist!")
        return None

    # Ensuring archive target path exists
    archive_folder.mkdir(parents=True, exist_ok=True)
    
    # 1. Scanning and organizing files by extension
    for file_path in source_folder.glob("*.*"):
        if file_path.is_file():
            ext_dir = archive_folder / file_path.suffix.lstrip(".").upper()
            ext_dir.mkdir(exist_ok=True)
            
            # Moving file into categorized extension subfolder
            target_dest = ext_dir / file_path.name
            shutil.copy(file_path, target_dest)
            print(f"[FILE ORGANIZED] Copied '{file_path.name}' -> '{ext_dir.name}/'")

    # 2. Creating compressed ZIP archive using shutil
    zip_output_base = archive_folder / "organized_backup"
    archive_path = shutil.make_archive(
        base_name=str(zip_output_base),
        format="zip",
        root_dir=archive_folder
    )
    
    print(f"\n[ARCHIVE SUCCESS] Created ZIP Bundle: '{Path(archive_path).name}'")
    return Path(archive_path)

# Executing File System Automation Setup
workspace_dir = Path.cwd() / "automation_workspace"
workspace_dir.mkdir(exist_ok=True)

# Pre-populating sample dummy operational files
(workspace_dir / "report_q1.csv").write_text("id,val\n1,100")
(workspace_dir / "invoice_9901.pdf").write_text("PDF_MOCK_DATA")
(workspace_dir / "audit_log.txt").write_text("AUDIT_LOG_TEXT")

backup_target = Path.cwd() / "backup_store"
automate_file_archiving(workspace_dir, backup_target)
OUTPUT
[FILE ORGANIZED] Copied 'report_q1.csv' -> 'CSV/'
[FILE ORGANIZED] Copied 'invoice_9901.pdf' -> 'PDF/'
[FILE ORGANIZED] Copied 'audit_log.txt' -> 'TXT/'

[ARCHIVE SUCCESS] Created ZIP Bundle: 'organized_backup.zip'

3. Excel Spreadsheet Automation via `openpyxl`

Microsoft Excel (`.xlsx`) is the universal format for enterprise business reports. To generate, edit, format, and parse Excel workbooks programmatically without requiring Microsoft Excel to be installed on server nodes, Python developers use the third-party library: `openpyxl`.

# Installing openpyxl library:
pip install openpyxl
    

1. Core Concepts: Workbook, Worksheet, and Cell Iteration

  • openpyxl.Workbook(): Creates a new, empty in-memory Excel workbook object.
  • wb.active or wb[sheet_name]: Accesses a target worksheet within the workbook.
  • ws.cell(row=r, column=c).value: Reads or writes data to explicit grid cell coordinates (1-indexed!).
  • ws.append([list_of_values]): Appends an entire row sequence to the bottom of the active sheet.
  • ws["C10"] = "=SUM(C2:C9)": Writes live Excel formulas directly into cells!
OPENPYXL_SPREADSHEET_DEMO.PY
import openpyxl
from openpyxl.styles import Font, PatternFill, Alignment
from pathlib import Path

def generate_financial_excel_report(output_filepath: Path):
    """
    Generates a styled, calculated Excel spreadsheet report programmatically using openpyxl.
    """
    # 1. Instantiating new Workbook and active worksheet
    wb = openpyxl.Workbook()
    ws = wb.active
    ws.title = "Q3_Sales_Summary"

    # 2. Writing Header Row with openpyxl Styles
    headers = ["Transaction ID", "Department", "Revenue ($)", "Tax Rate", "Net Amount ($)"]
    ws.append(headers)

    header_fill = PatternFill(start_color="1F2937", end_color="1F2937", fill_type="solid")
    header_font = Font(name="Arial", size=11, bold=True, color="FFFFFF")

    for col_idx in range(1, len(headers) + 1):
        cell = ws.cell(row=1, column=col_idx)
        cell.fill = header_fill
        cell.font = header_font
        cell.alignment = Alignment(horizontal="center")

    # 3. Appending Business Data Rows
    sales_data = [
        ["TX_1001", "Hardware", 12500.00, 0.18],
        ["TX_1002", "Software", 8400.00, 0.18],
        ["TX_1003", "Services", 3100.00, 0.18],
    ]

    for row_idx, row_data in enumerate(sales_data, start=2):
        ws.cell(row=row_idx, column=1, value=row_data[0])
        ws.cell(row=row_idx, column=2, value=row_data[1])
        ws.cell(row=row_idx, column=3, value=row_data[2])
        ws.cell(row=row_idx, column=4, value=row_data[3])
        # Injecting Excel Formula dynamically!
        ws.cell(row=row_idx, column=5, value=f"=C{row_idx}*(1+D{row_idx})")

    # 4. Appending Grand Total Summary Row with Excel Formula
    total_row = len(sales_data) + 2
    ws.cell(row=total_row, column=2, value="TOTAL:").font = Font(bold=True)
    ws.cell(row=total_row, column=3, value=f"=SUM(C2:C{total_row-1})").font = Font(bold=True)
    ws.cell(row=total_row, column=5, value=f"=SUM(E2:E{total_row-1})").font = Font(bold=True)

    # 5. Saving Workbook to disk
    wb.save(output_filepath)
    print(f"=== Excel Report Generated Successfully: '{output_filepath.name}' ===")

excel_file = Path.cwd() / "Q3_Financial_Report.xlsx"
generate_financial_excel_report(excel_file)
OUTPUT
=== Excel Report Generated Successfully: 'Q3_Financial_Report.xlsx' ===

4. Automated Email Notifications: `smtplib` & `email.message`

After generating spreadsheet reports or detecting system events, automation pipelines notify operators by sending automated email alerts via the Simple Mail Transfer Protocol (SMTP).

Python includes built-in email modules in its standard library:

  • email.message.EmailMessage: Constructs clean, modern MIME-compliant email objects (supporting HTML bodies, plain text fallbacks, custom headers, and file attachments).
  • smtplib.SMTP_SSL / smtplib.SMTP: Connects securely to corporate email servers (such as Gmail SMTP, Microsoft 365, or internal corporate relays) over encrypted TLS/SSL ports (465 or 587).
SMTP Security Best Practice: NEVER hardcode email passwords or SMTP credentials inside Python scripts! Always load passwords from host environment variables using os.environ.get("SMTP_PASSWORD")!
EMAIL_AUTOMATION_DEMO.PY
import os
import smtplib
from email.message import EmailMessage
from pathlib import Path

def construct_and_send_email_notification(
    recipient_email: str,
    subject_title: str,
    body_content: str,
    attachment_path: Path | None = None
) -> bool:
    """
    Constructs a modern MIME email message with optional file attachment
    and demonstrates sending logic structure using email.message and smtplib.
    """
    # 1. Building MIME Message Container
    msg = EmailMessage()
    msg["Subject"] = subject_title
    msg["From"] = "automation-bot@enterprise.corp"
    msg["To"] = recipient_email
    
    # Setting plain text body content
    msg.set_content(body_content)

    # 2. Attaching file payload if present
    if attachment_path and attachment_path.exists():
        file_bytes = attachment_path.read_bytes()
        msg.add_attachment(
            file_bytes,
            maintype="application",
            subtype="octet-stream",
            filename=attachment_path.name
        )
        print(f"[EMAIL ATTACHMENT] Attached file: '{attachment_path.name}' ({len(file_bytes)} bytes)")

    # 3. SMTP Server Transmission Logic (Simulated for local execution)
    smtp_server = os.environ.get("SMTP_SERVER", "smtp.office365.com")
    smtp_port = int(os.environ.get("SMTP_PORT", 587))
    smtp_user = os.environ.get("SMTP_USER", "bot@enterprise.corp")
    smtp_pass = os.environ.get("SMTP_PASSWORD", "DEV_PASS_PLACEHOLDER")

    print(f"=== Email Message Constructed Successfully ===")
    print(f"  From   : {msg['From']}")
    print(f"  To     : {msg['To']}")
    print(f"  Subject: {msg['Subject']}")
    print(f"  Body   : {body_content.strip()}")
    print(f"  Target : Ready for transmission via SMTP Server -> {smtp_server}:{smtp_port}")
    
    return True

# Testing Email Message Builder
demo_report = Path.cwd() / "Q3_Financial_Report.xlsx"
construct_and_send_email_notification(
    recipient_email="executive@enterprise.corp",
    subject_title="Q3 Financial Audit & Spreadsheet Report",
    body_content="Hello Team,\n\nPlease find attached the automated Q3 sales summary report spreadsheet.\n\nBest regards,\nAutomation Bot",
    attachment_path=demo_report
)
OUTPUT
[EMAIL ATTACHMENT] Attached file: 'Q3_Financial_Report.xlsx' (5382 bytes)
=== Email Message Constructed Successfully ===
  From   : automation-bot@enterprise.corp
  To     : executive@enterprise.corp
  Subject: Q3 Financial Audit & Spreadsheet Report
  Body   : Hello Team,

Please find attached the automated Q3 sales summary report spreadsheet.

Best regards,
Automation Bot
  Target : Ready for transmission via SMTP Server -> smtp.office365.com:587

5. Combining Automation Tasks with `match-case` Pattern Matching

Building scalable Robotic Process Automation (RPA) dispatchers involves accepting heterogeneous automation job requests and routing tasks cleanly using Python 3.10+ `match-case` Structural Pattern Matching.

MATCH_CASE_AUTOMATION_DISPATCHER.PY
from pathlib import Path

def dispatch_automation_job(job_task: tuple) -> str:
    """
    Routes office automation task tuples using Structural Pattern Matching.
    Demonstrates handling file operations, spreadsheet tasks, and emails dynamically.
    """
    match job_task:
        case ("ARCHIVE_FILES", str(src), str(dst)):
            return f"DISPATCH_ARCHIVE: Scanning '{src}' and bundling backup zip into '{dst}'."

        case ("GENERATE_SPREADSHEET", str(report_name), int(data_rows)):
            return f"DISPATCH_EXCEL: Creating Workbook '{report_name}.xlsx' with {data_rows} populated rows."

        case ("SEND_EMAIL", str(to_addr), str(subj), str(attach_path)) if attach_path.endswith(".xlsx"):
            return f"DISPATCH_EMAIL_EXCEL: Dispatching email to '{to_addr}' with Excel attachment '{attach_path}'."

        case ("SEND_EMAIL", str(to_addr), str(subj), _):
            return f"DISPATCH_EMAIL_TEXT: Dispatching text notification email to '{to_addr}'."

        case _:
            return f"UNRECOGNIZED_AUTOMATION_JOB: Unable to route payload: {job_task}"

# Testing Pattern Matched RPA Dispatcher
print("=== Pattern Matched Automation Job Execution Outputs ===")
print(dispatch_automation_job(("ARCHIVE_FILES", "/var/logs", "/backup/logs")))
print(dispatch_automation_job(("GENERATE_SPREADSHEET", "Monthly_Payroll", 150)))
print(dispatch_automation_job(("SEND_EMAIL", "ceo@corp.com", "Payroll Ready", "Payroll.xlsx")))
print(dispatch_automation_job(("SEND_EMAIL", "dev@corp.com", "Alert Notice", "None")))
OUTPUT
=== Pattern Matched Automation Job Execution Outputs ===
DISPATCH_ARCHIVE: Scanning '/var/logs' and bundling backup zip into '/backup/logs'.
DISPATCH_EXCEL: Creating Workbook 'Monthly_Payroll.xlsx' with 150 populated rows.
DISPATCH_EMAIL_EXCEL: Dispatching email to 'ceo@corp.com' with Excel attachment 'Payroll.xlsx'.
DISPATCH_EMAIL_TEXT: Dispatching text notification email to 'dev@corp.com'.

6. Frequently Asked Interview Questions with Answers

Q1: What is the primary difference between `shutil.copy()` and `shutil.copytree()` in Python?
Answer: shutil.copy(src, dst) copies a single standalone file object. shutil.copytree(src, dst) recursively copies an entire directory tree, including all sub-directories and nested files.
Q2: Which Python library is standard for reading and writing Excel (`.xlsx`) files programmatically?
Answer: The openpyxl library. It provides programmatic access to workbooks, worksheets, styles, font formatting, and allows injecting active Excel formulas (such as =SUM()) directly into worksheet cells.
Q3: How do `email.message.EmailMessage` and `smtplib` work together to send email notifications?
Answer: EmailMessage constructs the structured MIME email object (setting headers, body text, HTML formatting, and attachments). smtplib.SMTP or smtplib.SMTP_SSL handles the network protocol connection, authentication, and transmission of the message to the destination SMTP mail server.
Q4: How do you attach binary files (such as PDFs or Excel sheets) to an `EmailMessage` object?
Answer: By reading the file as raw bytes using path.read_bytes() and calling msg.add_attachment(bytes_data, maintype="application", subtype="octet-stream", filename=path.name).
Q5: Why should SMTP login passwords never be hardcoded in Python automation scripts?
Answer: Hardcoding email account passwords inside script source code risks exposing sensitive credentials in public version control repositories (Git). Credentials should be injected dynamically at runtime via host environment variables (using os.environ.get()).

7. Homework & Practical Assignments

Task 1: Automated Directory Cleanup and Compression Utility

Create a script named file_cleaner_task.py inside your lesson_56 folder:

  • Import shutil and pathlib.Path.
  • Define function archive_and_clean_logs(log_dir: Path, target_zip: Path) -> bool.
  • Scan log_dir for all .log files, copy them to a temporary backup directory, compress the backup using shutil.make_archive(), and delete the temporary folder.
  • Print confirmation logs with f-strings.

Task 2: Pattern-Matched RPA Task Dispatcher

Create a script named rpa_dispatcher_task.py:

  • Build function process_rpa_instruction(task_tuple: tuple) -> str parsing automation instructions.
  • Write a match-case dispatcher:
    • case ("EXCEL_TOTAL", filepath, col_letter) → Return confirmation string for generating Excel totals.
    • case ("EMAIL_ALERT", recipient, message) → Return confirmation string for sending alert email.
    • case ("CLEAN_TEMP", dir_path) → Return confirmation string for directory purge.
    • case _ → Return error string.
  • Test function across 4 sample task tuples and print output strings.

Task 3: Master Review Capstone Project — Production Enterprise Office Automation & RPA OS (`office_automation_os.py`)

Create a script named office_automation_os.py inside your lesson_56 folder. This assignment tests and integrates **ALL concepts learned across Lessons 1 through 56**.

Project Architectural Requirements Specification:

  1. Office Automation & RPA Architecture (Lesson 56):
    • Implement directory scanning, categorization, and ZIP archive creation using shutil and pathlib.Path.
    • Generate styled, calculated Excel report workbooks using openpyxl with formulas and custom styles.
    • Construct MIME email objects via email.message.EmailMessage with attachments and simulated SMTP transmission.
  2. Web Scraping Integration (Lesson 55):
    • Extract market data text elements from HTML documents using BeautifulSoup4 (`bs4`) to populate Excel report rows.
  3. HTTP APIs & requests Integration (Lesson 54):
    • Fetch remote operational parameters via requests.Session() with timeouts and error handling.
  4. SQLite Persistence Integration (Lesson 53):
    • Persist operational automation logs into an SQLite database table using parameterized SQL statements and sqlite3.Row.
  5. Security, Performance & Memory Hardening (Lesson 52):
    • Use __slots__ across automation data model classes for memory optimization.
    • Read SMTP secrets dynamically from environment variables using os.environ.
  6. Packaging & Distribution Integration (Lesson 51):
    • Include a programmatically generated pyproject.toml package specification string and an argparse CLI entry point structure.
  7. Clean Code, Documentation & Refactoring (Lesson 50):
    • Apply SOLID principles, DRY, and Google Style Docstrings across all functions and classes.
  8. Testing & Quality Assurance (Lessons 47-48):
    • Include unit tests verified via pytest fixtures and unittest.mock.
  9. Asyncio & Concurrency Integration (Lessons 45-46):
    • Incorporate thread pool workers or async event loops for parallel multi-attachment email processing.
  10. Temporal & RegEx Text Processing (Lessons 43-44):
    • Parse UTC-aware automation timestamps using datetime and zoneinfo.ZoneInfo.
    • Pre-compile RegEx patterns with Named Groups for parsing file names.
  11. Type Hints, Generics & Static Safety (Lesson 42):
    • Apply explicit modern type annotations (X | Y, list[str], dict[str, Any]) throughout all functions and classes.
  12. Metaprogramming, Closures & Decorators (Lessons 40-41):
    • Build function factories and 3-level configurable decorators with @functools.wraps.
  13. Iterators & Generators (Lesson 39):
    • Implement generator functions streaming file archive lists lazily with $O(1)$ memory.
  14. Full OOP Architecture (Lessons 32-38):
    • Define abstract base class BaseAutomationWorker(ABC) and concrete Data Classes AutomationJobRecord and EmailAudit.
    • Build composite manager OfficeAutomationOS composing storage drivers and custom context managers.
  15. Observability & Fault Tolerance (Lessons 29-31):
    • Set up multi-handler logging to console and office_automation.log file.
    • Incorporate developer assertions (assert) verifying file non-nullability.
    • Define custom exception hierarchy (OfficeAutomationOSError, SpreadsheetGenerationError).
  16. Context Managers & Persistence Layer (Lessons 27-30):
    • Use custom class-based context managers to manage temp directory cleanup.
    • Persist JSON payload backups to automation_db.json and export CSV reports to automation_audit.csv using pathlib.Path.
  17. Nested Collections & Comprehensions (Lessons 21-26):
    • Maintain in-memory registry dictionaries mapping Job IDs to Data Class Instances.
    • Use List and Dictionary Comprehensions to clean and transform records.
  18. Advanced Function Parameters & Scope (Lessons 15-17):
    • Structure logic into pure modular functions with type hints, docstrings, early return Guard Clauses, and *args / **kwargs logging.
  19. Indefinite & Definite Loops (Lessons 13-14):
    • Run the interactive CLI interface inside a continuous while True menu loop.
    • Iterate through output reports using for loops with enumerate() and .items().
  20. Pattern Matching CLI Dispatcher (Lesson 12):
    • Process user CLI command tokens inside a match-case block with office automation match guards:
      • case ["ARCHIVE", "DIR", src_dir, dst_dir] → Execute directory scanning and ZIP compression.
      • case ["EXCEL", "GENERATE", filename] → Build styled Excel report with openpyxl.
      • case ["EMAIL", "SEND", to_addr, subj, attach] → Construct and send MIME email with attachment.
      • case ["EXPORT", "CSV"] → Export completed automation job history to CSV.
      • case ["EXIT" | "QUIT"] → Terminate session safely using a sentinel flag.
      • case _ → Output command error message.
  21. Conditionals, Formatting & Foundations (Lessons 1-11):
    • Sanitize all inputs using .strip() and .upper().
    • Format tabular reports using f-strings with field width alignment specifiers (:<15, :>10) and clear visual borders.

8. File & Workspace Directory Structure

Standard Course Workspace Layout:

Ensure all exercise files are stored inside their corresponding lesson directories:

python_mastery_course/
│
├── lesson_01/ ... lesson_55/
│
└── lesson_56/
    ├── file_system_automation_demo.py
    ├── openpyxl_spreadsheet_demo.py
    ├── email_automation_demo.py
    ├── match_case_automation_dispatcher.py
    ├── file_cleaner_task.py          <-- (Task 1)
    ├── rpa_dispatcher_task.py        <-- (Task 2)
    └── office_automation_os.py       <-- (Task 3: Master Review Capstone)
        

9. What We Will Learn Next

Next Up: Lesson 57 — Web Development with Flask

Congratulations on completing Module 9 and mastering Office Automation, Spreadsheets, and Email Pipelines! We now enter Module 10: Web Application Development and Web Frameworks!

In the next lesson, we will cover:

  • Introduction to Web Application Development and WSGI (Web Server Gateway Interface).
  • Building lightweight web applications using the Flask micro-framework.
  • Defining Application Routes, URL Variables, and View Functions (`@app.route()`).
  • Parsing Request Payloads and Returning JSON API Responses (`flask.request`, `jsonify`).
  • Rendering Dynamic HTML Templates using the Jinja2 Templating Engine.
  • Combining HTTP Web Request Routes with match-case structural pattern matchers.

📝 Live Lesson Practice

HTML/CSS JavaScript Python C++ C PHP
⌨️ Practice Inputs (लाइव इनपुट भरें) (खाली होने पर RED, भरने पर GREEN underline)
💻 Code Editor (Monaco VS Code Engine)
👀 Live Preview
Address Contact

+91 7877547686

E-mail

onlinecbtportal@gmail.com

Helpline Number

+91 7877547686


Click To Download
Get it on Google Play

ऐप डाउनलोड करने
के लिए Google Play पर
उपलब्ध है

WhatsApp Chat