Smart Email Automation with Mistral-7B
A practical end-to-end Python pipeline automating lead extraction from scanned documents, LLM-powered tone refinement via OpenRouter, and rate-limited Windows COM Outlook dispatching.
01. The Real Problem
During career outreach or enterprise business development, professionals frequently encounter contact lists trapped inside non-selectable image formats (scanned PDF pages, screenshots of tables, and document prints). Manually transcribing dozens of email addresses and drafting tailored messages is repetitive and prone to typographical errors.
The goal of this project was to automate the entire funnel in Python:
- Parse scanned documents and images into clean tabular CSV contact lists using OCR.
- Programmatically enhance draft email copy using a modern open-weights instruction model (Mistral-7B) to maintain crisp, professional formatting.
- Dispatch personalized messages and attachments via a locally authenticated Microsoft Outlook desktop client with audit logging.
02. Verified Pipeline Workflow
Inspection of image_to_csv.py, aitesting.py, and test2sendmail.py reveals a 4-stage sequential automation flow:
Image to Text
Tesseract OCR + Regex extraction into email.csv
Mistral-7B
OpenRouter API rephrases subject & body
Outlook COM
Win32 COM API attaches PDF & dispatches
Logging
ISO timestamp & status recorded in CSV
03. OCR & Regex Sanitization
In image_to_csv.py, images are loaded via PIL (Python Imaging Library) and processed through pytesseract.image_to_string(). A regular expression extracts all valid email formats:
def extract_emails(text):
"""Extract email addresses from text using regex"""
email_pattern = r'[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+'
return re.findall(email_pattern, text)
In test2sendmail.py, the Pandas reader contains defensive fallback logic to handle CSVs with or without headers, strips surrounding whitespace, and filters out non-email strings before any mail transaction begins.
04. Mistral-7B AI Enhancement
Rather than sending rigid static templates, the script integrates OpenRouter's OpenAI-compatible completions API to invoke mistralai/mistral-7b-instruct:free. The function parses the model output into distinct subject line and markdown body components:
def enhance_email(subject, body):
prompt = (
f"Improve the following job application email for clarity, professionalism, and impact. "
f"Return a subject line and a body in markdown format. "
f"Subject: {subject}\n\nBody:\n{body}"
)
completion = client.chat.completions.create(
model="mistralai/mistral-7b-instruct:free",
messages=[{"role": "user", "content": prompt}]
)
content = completion.choices[0].message.content
# Parse subject and body lines from model response
lines = content.splitlines()
...
return new_subject, new_body
05. Dispatch Engine & Throttling
Mail dispatching is executed through the Windows COM automation bridge: win32com.client.Dispatch('outlook.application'). This leverages the local desktop Outlook authentication, bypassing SMTP credential handshakes.
Crucially, to prevent local mail-client flooding, the dispatch loop incorporates intentional spacing:
- Throttling Delay: Enforces
time.sleep(10)between successive transmissions. - Safe Attachment Resolution: Validates file existence using
pathlib.Path(attachment_path).exists()and resolves absolute paths prior to callingmail.Attachments.Add(). - Delivery Telemetry: Records every outcome (either
"Sent"or"Failed: <error>") alongside ISO 8601 timestamps inemail_log.csv.
06. Security, Limitations & ISP Constraints
Authentic Engineering Boundaries
- No Deliverability Guarantee: This application interacts solely with the local Outlook client. It does not bypass email service provider spam filters, SPF/DKIM policies, or organizational inbox firewalls.
- OS Compatibility: Because it depends on the Windows COM interface (
win32com), this automation runs exclusively on Windows with an installed, authenticated Microsoft Outlook profile. - Security Caution: In early script iterations, API keys were placed directly in script headers. For production hardening, credentials should strictly be managed via environment variables (e.g.
os.getenv("OPENROUTER_API_KEY")).