简体   繁体   English

在使用 python 的电子邮件和 smtplib 包发送的电子邮件中,EmailMessage 无法正确显示

[英]EmailMessage doesn't show correctly in the sent emails with python's email and smtplib packages

My emails can be correctly sent but don't show correctly in the receiver mails.我的电子邮件可以正确发送,但在接收方邮件中显示不正确。 It looks like this:它看起来像这样:

To: =?utf-8?b?..?= <....com> MIME-Version: 1.0 Content-Type: multipart/mixed; To: =?utf-8?b?..?= <....com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============5404281335870522242=="边界="================5404281335870522242=="

--===============5404281335870522242== Content-Type: text/plain; --==============5404281335870522242== 内容类型:文本/普通; charset="utf-8" Content-Transfer-Encoding: base64 charset="utf-8" 内容传输编码:base64

5bCK5pWs55qE5a2U6LaF5YW... 5bCK5pWs55qE5a2U6LaF5YW...

--===============5404281335870522242== Content-Type: image/png Content-Transfer-Encoding: base64 Content-Disposition: attachment; --================5404281335870522242== 内容类型:图像/png 内容传输编码:base64 内容处理:附件; filename="user.png" MIME-Version: 1.0文件名 =“user.png” MIME 版本:1.0

iVBORw0KGgo... iVBORw0KGgo...

The MIME string is directly shown except the Subject and the From line(It is shown after the To ) as well as all bodies in plain text. MIME 字符串直接显示,除了SubjectFrom行(显示在To )以及纯文本中的所有正文。

There's my code:这是我的代码:

import smtplib
import ssl
import mimetypes
from pathlib import Path
from email.message import EmailMessage
from email.utils import formataddr
import time

class EmailSender:
    PORT = 465
    CONTEXT = ssl.create_default_context()

    def __init__(
        self,
        username,
        password,
        host,
    ):
        self.username = username
        self.password = password
        self.host = host
        self.mails = []

    def _add_name_header(self, name="", mail_addr=""):
        if name:
            return formataddr((name, mail_addr))
        else:
            return mail_addr

    def add_mail(
        self,
        from_email="",
        from_name="",
        to_email="",
        to_name="",
        subject="",
        message_txt="",
        files=None,
    ):
        msg = EmailMessage()
        msg["Subject"] = subject
        msg["From"] = self._add_name_header(from_name, from_email)
        msg["To"] = self._add_name_header(to_name, to_email)
        msg.set_content(message_txt)

        if not files is None:
            for file_obj in files:
                if file_obj.exists():
                    file = str(file_obj)
                    ctype, encoding = mimetypes.guess_type(file)
                    if ctype is None or encoding is not None:
                        # No guess could be made, or the file is encoded (compressed), so use a generic bag-of-bits type.
                        ctype = "application/octet-stream"
                    maintype, subtype = ctype.split("/", 1)
                    with file_obj.open("rb") as fp:
                        msg.add_attachment(
                            fp.read(),
                            maintype=maintype,
                            subtype=subtype,
                            filename=file_obj.name,
                        )

        self.mails.append(msg)

    def send(self, time_interval=1):
        with smtplib.SMTP_SSL(
            host=self.host, port=self.PORT, context=self.CONTEXT
        ) as server:
            try:
                server.login(user=self.username, password=self.password)
            except Exception as e:
                # Need process errors
                raise e
            for msg in self.mails:
                server.send_message(msg)
                time.sleep(time_interval)

And I just do:我只是这样做:

sender = EmailSender(
        username, password, host="smtp.163.com"
)

files = list(Path("D:/").glob("*.pdf"))

sender.add_mail(
        from_email, from_name, to_email, to_name, subject, message_txt, files=None
)
sender.send(time_interval=10)

I'm the OP of the question.我是问题的 OP。 I just solved this problem by myself and I'd share the solution.我只是自己解决了这个问题,我会分享解决方案。

TLNR: Non-Ascii chars are used in my mails so use msg = EmailMessage(EmailPolicy(utf8=True)) instead of msg = EmailMessage() . TLNR:我的邮件中使用了非 Ascii 字符,因此请使用msg = EmailMessage(EmailPolicy(utf8=True))而不是msg = EmailMessage()

I misunderstood these sentences in the doc of SMTP.send_message :我误解了SMTP.send_message文档中的这些句子:

If any of the addresses in from_addr and to_addrs contain non-ASCII characters and the server does not advertise SMTPUTF8 support, an SMTPNotSupported error is raised.如果 from_addr 和 to_addrs 中的任何地址包含非 ASCII 字符并且服务器不通告 SMTPUTF8 支持,则会引发 SMTPNotSupported 错误。 Otherwise the Message is serialized with a clone of its policy with the utf8 attribute set to True, and SMTPUTF8 and BODY=8BITMIME are added to mail_options.否则,将使用 utf8 属性设置为 True 的策略克隆序列化消息,并将 SMTPUTF8 和 BODY=8BITMIME 添加到 mail_options。

Since I add a non-ASCII header to my address, I believe that smtplib will automatically use the utf8 policy for me.由于我在地址中添加了非 ASCII 标头,因此我相信smtplib会自动为我使用 utf8 策略。 But in the file smtplib.py I saw this:但是在文件smtplib.py我看到了这个:

if from_addr is None:
    # Some code
    from_addr = email.utils.getaddresses([from_addr])[0][1]
if to_addrs is None:
    # Some code
    to_addrs = [a[1] for a in email.utils.getaddresses(addr_fields)]
# Some code
international = False
try:
    "".join([from_addr, *to_addrs]).encode("ascii")
except UnicodeEncodeError:
    # Some code
    international = True

That is, the function only checks if the address parts have non-ASCII chars but not along with the header names.也就是说,该函数仅检查地址部分是否具有非 ASCII 字符,但不检查标题名称。

After that, the message is dealt with as pure ASCII content, that's maybe no problem, I have no idea why, but somohow, many extra /r chars are inserted before and after the To:xxx line , which makes the smtp server think this as a separator maybe?之后,消息被处理为纯 ASCII 内容,这可能没问题,我不知道为什么,但是somohow,To:xxx行之前和之后插入了许多额外的/r字符,这使得 smtp 服务器认为这一点也许作为分​​隔符? And finally caused the problem.并最终导致了问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用 Python smtplib 和 EmailMessage() 发送电子邮件 - Sending emails using Python smtplib and EmailMessage() 在Python的smtplib软件包中,如果发送的电子邮件退回,是否可以创建通知? - In Python's smtplib package, is there a way to create a notification if sent emails bounce? smtplib 不发送 email | Python - smtplib doesn't send an email | Python 计算使用 smtplib python 发送的电子邮件数量 - count number of emails sent using smtplib python 如何在Outlook“已发送邮件”文件夹中看到使用Python的smtplib发送的电子邮件? - How can I see emails sent with Python's smtplib in my Outlook Sent Items folder? Python smtplib:如何发送类似于从电子邮件帐户发送的电子邮件的消息 - Python smtplib: How to send messages that look like emails sent from email account 为什么发送电子邮件时不显示消息? - smtplib - Python - Why doesn't a message appear when sending an email? - smtplib - Python 用smtplib发送和接收的python电子邮件没有内容 - python email sent and received with smtplib has no content 无法在使用 python smtplib/电子邮件发送的 outlook 2013 中的 email 中显示嵌入图像 - Can't display an embedded image in an email in outlook 2013 sent using using python smtplib/email smtplib不会在无效的电子邮件地址上失败 - smtplib doesn't fail on invalid email addresses
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM