smtplib sends blank message if the message contain certain characters
The problem is that smtplib
is not putting a blank line between the message header and the message body as shown by in the "Show Original" form of my test:
Return-Path: <[email protected]>
Received: **REDACTED**
Fri, 03 Aug 2012 06:56:20 -0700 (PDT)
Message-ID: <[email protected]>
Date: Fri, 03 Aug 2012 06:56:20 -0700 (PDT)
From: [email protected]
http: //www.example.com
Although this is a legal mail header, Mail Transfer Agents and Mail User Agents should ignore apparent header fields they don't understand. And because the RFC822 header continues until the first blank line and http:
looks like a header line, it is parsed as if it were a header. If given a newline:
mensaje = '\nhttp://www.example.com'
Then it works as expected. Although email technically only needs the "envelope" as provided by smtplib
the contents of the mail should be more complete if you expect your recipients (and their mailers) to treat the message nicely, you should probably use the email module to generate the body.
added
Based on the doctest in smtplib.py
it looks as if this is an intentional feature allowing the caller of sendmail()
to append to the header:
>>> msg = '''\\
... From: [email protected]
... Subject: testin'...
...
... This is a test '''
>>> s.sendmail("[email protected]", tolist, msg)
Where the From:
and Subject:
lines are part of the "nice" headers I mentioned above.
The proper solution is to use the Python email
library to create a valid message, instead of painstakingly learning (or wildly guessing at random) how to construct a valid MIME message structure by joining together pieces of text.
A trivial RFC822 message which contains only ASCII can easily be created with
"From: {0}\nTo: {1}\nSubject: {2}\n\n{3}".format(
fromaddr, toaddr,
"Hello, I am the exiled prince of Ubandingba",
"http://clickme.example.net/scam/")
but as soon as you need anything with other character sets, lines longer than some 80 characters, content types other than plain text, or in general anything more advanced than plain text English-language email as it was in 1990, the code should look something like
from email.message import EmailMessage
msg = EmailMessage()
msg["from"] = fromaddr
msg["to"] = toaddr
msg["subject"] = "You have been nominated for the Nobel prize"
msg.set_content("http://scam.example.org/clickme")
which is admittedly slightly more verbose, but also infinitely more versatile, robust, and extensible.
This uses the EmailMessage
API which was officially introduced in Python 3.6. New code should probably target this platform rather than the legacy email.Message
module from earlier versions, although most online code examples you can find will be for the older Python library. See the Python email
examples documentation for some quick examples.