问题
from email.message import EmailMessage
from email.headerregistry import Address
msg = EmailMessage()
msg['From'] = Address("Pepé Le Pew", "pepe", "example.com")
msg['To'] = (
Address("Penelope Pussycat", "penelope", "example.com")
, Address("Fabrette Pussycat", "fabrette", "example.com")
)
msg['Subject'] = 'This email sent from Python code'
msg.set_content("""\
Salut!
Cela ressemble à un excellent recipie[1] déjeuner.
[1] http://www.yummly.com/recipe/Roasted-Asparagus-Epicurious-203718
--Pepé
""")
print(msg)
The above code produces an email message that uses base64 encoding. How to disable it? How to remove the field of MIME-Version?
Will the encoding of "Pepé" be correctly interpreted by the recipient? If not, what is the correct way to ensure its encoding is interpreted by the recipient correctly?
From: Pepé Le Pew <pepe@example.com>
To: Penelope Pussycat <penelope@example.com>,
Fabrette Pussycat <fabrette@example.com>
Subject: This email sent from Python code
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: base64
MIME-Version: 1.0
CQlTYWx1dCEKCgkJQ2VsYSByZXNzZW1ibGUgw6AgdW4gZXhjZWxsZW50IHJlY2lwaWVbMV0gZMOp
amV1bmVyLgoKCQlbMV0gaHR0cDovL3d3dy55dW1tbHkuY29tL3JlY2lwZS9Sb2FzdGVkLUFzcGFy
YWd1cy1FcGljdXJpb3VzLTIwMzcxOAoKCQktLVBlcMOpCgkJCg==
回答1:
You absolutely must not remove the MIME-Version:
header; it's what identifies this as a MIME message.
The From:
header should indeed be RFC2047-encoded, and the documentation suggests that it will be "when the message is serialized". When you print(msg)
you are not properly serializing it; you want print(msg.as_string())
which does exhibit the required serialization.
When it comes to the transfer encoding, Python's email
library has an unattractive penchant for using base64
for content which could very well be encoded as quoted-printable instead. You can't really reliably send the content completely unencoded (though if you wanted to, the MIME 8bit
or binary
encodings would be able to accommodate that; but for backwards compatibility, SMTP requires everything to be encoded into a 7-bit representation).
In the old email
library, various shenanigans were required to do this, but in the new EmailMessage
API introduced in Python 3.6, you really only have to add cte='quoted-printable
to the set_content
call.
from email.message import EmailMessage
from email.headerregistry import Address
msg = EmailMessage()
msg['From'] = Address("Pepé Le Pew", "pepe", "example.com")
msg['To'] = (
Address("Penelope Pussycat", "penelope", "example.com")
, Address("Fabrette Pussycat", "fabrette", "example.com")
)
msg['Subject'] = 'This email sent from Python code'
msg.set_content("""\
Salut!
Cela ressemble à un excellent recipie[1] déjeuner.
[1] http://www.yummly.com/recipe/Roasted-Asparagus-Epicurious-203718
--Pepé
""", cte="quoted-printable") # <-- notice added parameter
print(msg.as_string()) # <-- properly serialize
Unfortunately, figuring this out from the documentation is next to impossible. The documentation for set_content basically just defers to the policy which obscurely points to the raw_data_manager (if you even notice the link) ... where finally you hopefully notice the presence of the cte
keyword argument.
Demo: https://ideone.com/eLAt11
(As an aside, you might also want to replace('\n ', '\n')
in the body text.)
If you go for an 8bit
or binary
content transfer encoding, the difference between them is that the former has a line length limit (max 900-something characters) whereas the latter is completely unconstrained. But you need to be sure that the entire SMTP transfer path is 8-bit clean (at which point you might as well pivot to Unicode email / ESMTP SMTPUTF8
entirely).
For your possible entertainment, here are some old questions with crazy hacks for Python 3.5 and earlier.
来源:https://stackoverflow.com/questions/66039715/python3-email-message-to-disable-base64-and-remove-mime-version