Email Module¶
The email module provides utilities for constructing and parsing email messages.
Complexity Reference¶
| Operation | Time | Space | Notes |
|---|---|---|---|
message_from_string() |
O(n) | O(n) | n = email size |
message_from_file() |
O(n) | O(n) | n = file size |
email.parser.Parser() |
O(n) | O(n) | Parse email |
EmailMessage() |
O(1) | O(1) | Create message |
set_content() |
O(n) | O(n) | n = content size |
get_payload() |
O(n) | O(n) | n = payload size |
Common Operations¶
Parsing Email Messages¶
from email import message_from_string
# O(n) where n = email string length
email_text = """From: sender@example.com
To: recipient@example.com
Subject: Test Email
Hello, this is a test email.
"""
message = message_from_string(email_text)
# O(h) field access where h = number of headers (linear search)
from_addr = message['From'] # 'sender@example.com'
to_addr = message['To'] # 'recipient@example.com'
subject = message['Subject'] # 'Test Email'
# O(n) get full payload where n = size
body = message.get_payload()
Parsing Email from File¶
from email import message_from_file
# O(n) where n = file size
with open('email.eml', 'r') as f:
message = message_from_file(f)
# O(h) access headers (linear search through header list)
subject = message['Subject']
# O(n) to get payload
body = message.get_payload()
Creating Email Messages¶
from email.message import EmailMessage
# O(1) to create
message = EmailMessage()
# O(n) to set each field where n = value length
message['Subject'] = 'Hello' # O(n)
message['From'] = 'sender@ex.com' # O(n)
message['To'] = 'recip@ex.com' # O(n)
message['Date'] = 'Mon, 1 Jan 2024'# O(n)
# O(n) to set content where n = content size
message.set_content('This is the email body')
# O(n) to convert to string where n = message size
email_str = message.as_string()
Handling Multipart Messages¶
from email.message import EmailMessage
# O(1) to create
message = EmailMessage()
# O(n) to set headers
message['Subject'] = 'Mixed Content'
# O(n) to set main content
message.set_content('This is the main message')
# O(n) to attach files where n = file size
# Add HTML alternative - O(n)
message.add_alternative(
'<html><body>This is <b>HTML</b></body></html>',
subtype='html'
)
# O(n) to attach attachment where n = file size
with open('attachment.pdf', 'rb') as attachment:
message.add_attachment(
attachment.read(),
maintype='application',
subtype='octet-stream',
filename='attachment.pdf'
)
# O(n) to convert to string
email_str = message.as_string()
Common Use Cases¶
Extract Email Information¶
from email import message_from_string
def extract_email_info(email_text):
"""Extract key information - O(n)"""
# O(n) to parse where n = email size
message = message_from_string(email_text)
# O(h) field access per header (linear search)
info = {
'from': message['From'],
'to': message['To'],
'subject': message['Subject'],
'date': message['Date'],
# O(n) to get body
'body': message.get_payload()
}
return info
Build Email with Attachments¶
from email.message import EmailMessage
import os
def build_email_with_files(to_addr, files):
"""Build email with multiple attachments - O(n)"""
message = EmailMessage()
# O(n) to set headers where n = header size
message['Subject'] = 'Files'
message['From'] = 'sender@example.com'
message['To'] = to_addr
# O(1) to set text body
message.set_content('See attached files')
# O(k*n) where k = file count, n = avg file size
for filepath in files:
if os.path.exists(filepath):
# O(n) per file to attach
with open(filepath, 'rb') as f:
data = f.read()
filename = os.path.basename(filepath)
message.add_attachment(
data,
maintype='application',
subtype='octet-stream',
filename=filename
)
return message
# Usage - O(n*k) where k = files
message = build_email_with_files(
'recipient@example.com',
['report.pdf', 'data.csv', 'image.png']
)
Parse Complex Email¶
from email import message_from_string
def extract_all_parts(email_text):
"""Extract all message parts - O(n)"""
# O(n) to parse
message = message_from_string(email_text)
parts = {
'headers': {},
'text': None,
'html': None,
'attachments': []
}
# O(n) to extract headers
for key, value in message.items():
parts['headers'][key] = value
# O(k) where k = number of parts
if message.is_multipart():
for part in message.iter_parts(): # O(k)
content_type = part.get_content_type()
# O(n) per part to get payload
payload = part.get_payload(decode=True)
if content_type == 'text/plain':
parts['text'] = payload.decode('utf-8')
elif content_type == 'text/html':
parts['html'] = payload.decode('utf-8')
elif content_type == 'application/octet-stream':
filename = part.get_filename()
parts['attachments'].append({
'filename': filename,
'data': payload
})
else:
# Single part - O(n)
parts['text'] = message.get_payload(decode=True)
return parts
Performance Tips¶
Cache Parsed Messages¶
from email import message_from_string
class EmailCache:
"""Cache parsed emails - O(1) lookup"""
def __init__(self):
self._cache = {}
def get_message(self, email_id, email_text):
"""O(1) if cached, O(n) first time"""
if email_id not in self._cache:
# O(n) first parse
self._cache[email_id] = message_from_string(email_text)
return self._cache[email_id]
# Usage
cache = EmailCache()
msg = cache.get_message(1, email_text) # O(n)
msg = cache.get_message(1, email_text) # O(1)
Process Large Email Streams¶
from email import message_from_file
def process_emails_stream(file_path):
"""Process multiple emails - O(k*n)"""
processed = []
# O(k*n) where k = emails, n = avg email size
with open(file_path, 'r') as f:
while True:
# O(n) per email
message = message_from_file(f)
if not message:
break
# Process email - O(n)
processed.append({
'subject': message['Subject'],
'from': message['From']
})
return processed
Version Notes¶
- Python 2.6+: Basic email module
- Python 3.6+: EmailMessage (recommended over older Message)
- Python 3.x: Full Unicode support
Related Documentation¶
- SMTP Client - Sending emails
- Base64 Module - Encoding attachments
- Html Module - HTML email parsing