Consider the following example to send an email via smtplib and email libraries in Python 3:
import smtplib
from email.message import EmailMessage
# Make the email:
msg = EmailMessage()
msg.set_content("""
Hi,
From foo
from bar
From baz
""")
msg['Subject'] = 'Example'
msg['From'] = "[email protected]"
msg['To'] = "[email protected]"
# Send the message via our own SMTP server.
s = smtplib.SMTP('localhost')
s.send_message(msg)
s.quit()
This will produce an email that looks like this:
Message-ID: <...>
Date: Thu, 17 Mar 2022 12:01:47 -0700 (PDT)
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 7bit
MIME-Version: 1.0
Subject: Example
From: [email protected]
To: [email protected]
Hi,
>From foo
from bar
From baz
Note how From
was turned to >From
in the body of the email if it is in the beginning of a line. I would like to not put the >
in there if there is From used in the email text. I suspect this is to prevent the from
being injected in the body if it was not defined in the headers but in my case it is defined.
Interestingly, this is not in the EmailMessage
itself:
>>> print(msg)
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 7bit
MIME-Version: 1.0
Subject: Example
From: [email protected]
To: [email protected]
Hi,
From foo
from bar
From baz
It seems the \nFrom
in the body is turned to \n>From
in the method SMTP(...).send_message
and it is not caused by the email policy in the message itself.
So the question is how to stop replacing the \nFrom
with \n>From
in the text body when sending emails.
CodePudding user response:
I found the answer and decided to document it if someone else stumbles on the same issue. In short, the answer is that there is not much you can do.
Basically this is what happens in smtplib.SMTP.send_message:
def send_message(self, msg, from_addr=None, to_addrs=None,
mail_options=(), rcpt_options=()):
...
else:
g = email.generator.BytesGenerator(bytesmsg)
g.flatten(msg_copy, linesep='\r\n')
Note how the generator is created by just passing the bytesmsg
as an argument.
Then the initiation of the generator:
def __init__(self, outfp, mangle_from_=None, maxheaderlen=None, *,
policy=None):
...
if mangle_from_ is None:
mangle_from_ = True if policy is None else policy.mangle_from_
self._fp = outfp
self._mangle_from_ = mangle_from_
self.maxheaderlen = maxheaderlen
self.policy = policy
Only the outfp
is passed (the bytesmsg
). The policy is None thus the mangle_from_
is always True
in the smtplib's send_message
method.
After a couple of method calls, a method is called that executes this:
...
if self._mangle_from_:
payload = fcre.sub('>From ', payload)
self._write_lines(payload)
...
This adds the >
in front of n\From
in the text content of an email.
Therefore, it seems one cannot get rid of replacing From
to >From
in the text body. You may subclass the method, copy the code and fix the policy yourself but that won't be clean.