Python smtplib: Missing Date/Message-ID Headers Break Mail Clients¶
Problem¶
Emails sent via Python's smtplib and EmailMessage appear on some mail clients but not others. The emails are delivered to the server and visible in Maildir, but specific clients silently suppress them.
Root Cause¶
Python's EmailMessage does not automatically add Date: or Message-ID: headers. These are required by RFC 5322. Without them:
- SpamAssassin flags
MISSING_DATEandMISSING_MID, and may setX-Spam-Flag: YESeven if the overall score is below the spam threshold - Mail clients (e.g., Spark) may filter on the spam flag header and silently hide the message — no Junk folder, just invisible
- Other clients (e.g., iPhone Mail, some Spark builds) may be more lenient and display the message anyway
This creates a confusing situation where the same email appears on one device but not another, despite both using the same IMAP account.
Fix¶
Always include Date and Message-ID headers when constructing emails with EmailMessage:
import smtplib
from email.message import EmailMessage
from email.utils import formatdate, make_msgid
msg = EmailMessage()
msg['Subject'] = 'Your subject here'
msg['From'] = 'sender@example.com'
msg['To'] = 'recipient@example.com'
msg['Date'] = formatdate(localtime=True)
msg['Message-ID'] = make_msgid(domain='example.com')
msg.set_content('Email body here')
with smtplib.SMTP('mail.example.com', 25) as s:
s.send_message(msg)
Verification¶
After applying the fix, check that SpamAssassin no longer flags the headers:
# Check email headers on the mail server
grep -E 'MISSING_DATE|MISSING_MID|X-Spam' /var/vmail/domain/user/cur/<message-file>
A clean message should show X-Spam-Status: No with no MISSING_DATE or MISSING_MID in the test list.
Key Takeaway¶
Python's EmailMessage is a low-level builder — it trusts you to set all required headers. Unlike higher-level mail libraries or webmail interfaces, it will happily send a message with no date or message ID. Always add both explicitly in any script that sends email via smtplib.