Introduction

I spend too much time crafting emails—whether it’s polite follow-ups, detailed updates, or quick replies. I decided to build a local assistant to draft and summarize emails directly on my laptop. No more worrying about corporate emails floating to third-party services, and I get custom templates that match my style.

Why a Local Email Assistant?

  • Corporate Privacy: My emails, recipients, and content stay within my network.
  • Personal Style: I can tweak the prompt to always include my signature, preferred greetings, and tone.
  • Efficiency: Turn bullet points into polished paragraphs and auto-summarize long threads.

Pipeline Overview

  1. Email Data Ingestion – Pull emails via IMAP or read local .eml files.
  2. Summarization & Context Extraction – Summarize long threads for context.
  3. Prompt Templates – Define generic templates for reply, follow-up, new email.
  4. Generation & Send – Call local LLM, review draft, and send via SMTP.

I’ll run through each component with code snippets and my personal workflow notes.


1. Email Data Ingestion

I use imaplib to fetch recent emails or a local directory of .eml files for testing.

import imaplib
import email

IMAP_SERVER = 'imap.company.com'
USERNAME = 'me@company.com'
PASSWORD = 'password'

# Connect and fetch
mail = imaplib.IMAP4_SSL(IMAP_SERVER)
mail.login(USERNAME, PASSWORD)
mail.select('inbox')

typ, data = mail.search(None, 'UNSEEN')
email_ids = data[0].split()

raw_emails = []
for eid in email_ids:
    typ, msg_data = mail.fetch(eid, '(RFC822)')
    raw_emails.append(email.message_from_bytes(msg_data[0][1]))

# Or read .eml files locally
# raw_emails = [email.message_from_file(open(path)) for path in os.listdir('emails/')]
print(f"Fetched {len(raw_emails)} new emails.")

I parse sender, date, subject, and the concatenated thread text for summarization.


2. Summarization & Context Extraction

Why: I need a quick summary of long threads so the assistant knows what’s happened so far.

from transformers import pipeline

summarizer = pipeline('summarization', model='facebook/bart-large-cnn', device=0)

def summarize_thread(email_messages):
    full_thread = '\n'.join([msg.get_payload(decode=True).decode('utf-8', errors='ignore')
                              for msg in email_messages])
    summary = summarizer(full_thread, max_length=100, min_length=20, do_sample=False)
    return summary[0]['summary_text']

# Example
thread_summary = summarize_thread(raw_emails)
print("Thread Summary:\n", thread_summary)

I sometimes chunk very long threads, but usually bart-large-cnn handles up to ~3k tokens fine.


3. Prompt Templates

I keep a set of Jinja2 templates for different scenarios:

-- reply.template --
Subject: Re: {{ subject }}

Hi {{ recipient_name }},

{{ body }}

Thanks,
{{ my_name }}

In code:

from jinja2 import Template

template_str = open('reply.template').read()
tmpl = Template(template_str)

prompt_input = tmpl.render(
    subject=subject,
    recipient_name='Alice',
    body=thread_summary,
    my_name='Me'
)

I swap out body with bullet lists or questions depending on follow-up vs. new mail.


4. Generation & Sending

I send the prompt to a text-generation pipeline and then hand off to smtplib after review.

from transformers import pipeline
import smtplib
from email.mime.text import MIMEText

generator = pipeline('text-generation', model='gpt2-medium', device=0)

# Generate draft
draft = generator(prompt_input, max_length=300)[0]['generated_text']
print("Draft Email:\n", draft)

# After manual review... send
msg = MIMEText(draft)
msg['Subject'] = f"Re: {subject}"
msg['From'] = USERNAME
msg['To'] = recipient_email

smtp = smtplib.SMTP('smtp.company.com', 587)
smtp.starttls()
smtp.login(USERNAME, PASSWORD)
smtp.send_message(msg)
smtp.quit()

I usually print the draft, edit minor tweaks, then press Enter to send from a small CLI wrapper.


Wrapping Up

This local email assistant saves me hours of repetitive writing and keeps all my sensitive content in-house. Next, I’ll experiment with integrating Firefox or Thunderbird plugins so I can draft directly in my mail client.