- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我们有一个向客户端发送电子邮件的 Web 应用程序,该 Web 应用程序使用 Flask 邮件框架来处理。大约 2 周前,我们的 Web 应用程序无法向客户和我们自己的团队发送电子邮件。我们使用 Office 365 的 Outlook 作为我们的发件人。
Remote Server returned '554 5.6.0 Corrupt message content; STOREDRV.Deliver.Exception:ConversionFailedException; Failed to process message due to a permanent exception with message Content conversion: Corrupt summary TNEF content. ConversionFailedException: Content conversion: Corrupt summary TNEF content. [Stage: PromoteCreateReplay]' Original message headers:
这是发件人在被指示发送电子邮件后收到的错误消息。我们联系了我们的 Office 365 管理员,Microsoft 告诉他我们的 Web 应用程序的安全性不符合 Microsoft 的要求/协议(protocol)。
问题是 Flask 邮件是否使用旧的安全协议(protocol)或配置不能很好地与 Microsoft Outlook 一起工作?
最佳答案
Outlook.com/Office365 错误消息没有多大帮助,因为它可以指示任何数量的问题。它表明 Microsoft 邮件服务器对电子邮件打包的某些方面( header 、附件等)不满意,并且它们的解析器在某处出错。他们的错误消息在提供的细节方面几乎毫无用处。我认为这是一个安全问题的断言是无稽之谈; Flask-Mail 使用经过充分测试的 Python 标准库 email
和 smtplib
包通过 TLS 加密连接发送电子邮件。
对于 Heroku 上的 Flask-Mail,我将问题追溯到 Heroku Dyno 机器上生成的 Message-ID header 。该问题不仅限于 Heroku,但是,您会在任何具有长主机名 的主机上看到此问题。您典型的 Heroku dyno 主机名以完整的 UUID 开头,再加上另外 5 个左右的组件,例如aaf39fce-569e-473a-9453-6862595bd8da.prvt.dyno.rt.heroku.com
。
此主机名用于为每封电子邮件生成的 Message-ID header 。 Flask-Mail 包使用标准 email.utils.make_msgid()
function生成 header ,默认情况下使用当前主机名。然后这会产生一个 Message-ID header ,例如:
Message-ID: <154810422972.4.16142961424846318784@aaf39fce-569e-473a-9453-6862595bd8da.prvt.dyno.rt.heroku.com>
这是一个 110 个字符长的字符串。这对于电子邮件 header 来说是一个小问题,因为电子邮件 RFC 声明 header 应该限制为 78 个字符。但是,有一些方法可以解决这个问题;对于超过 77 个字符的 header 值,您可以使用 RFC 5322 中的规定折叠 标题。折叠可以使用多个RFC 2047 在多行上编码单词。这就是这里发生的事情,上面的电子邮件标题变成了
Message-ID: =?utf-8?q?=3C154810422972=2E4=2E16142961424846318784=40aaf39fce-?=
=?utf-8?q?569e-473a-9453-6862595bd8da=2Eprvt=2Edyno=2Ert=2Eheroku=2Ecom=3E?=
其中 78 和 77 个字符现在符合电子邮件 MIME 标准。
在我看来,所有这些都符合标准,并且是处理邮件 header 的有效方法。或者至少是其他邮件提供商可以容忍并正确处理的东西,但 Microsoft 的邮件服务器没有这个。他们真的不喜欢上面的 RFC2047 编码的 Message-ID header ,并尝试将正文包装在 TNEF winmail.dat 附件中。这并不总是有效,所以您最终会收到非常神秘的 554 5.6.0 Corrupt message content 错误消息。我认为这是一个 Microsoft 错误;我不能 100% 确定电子邮件 RFC 是否允许使用编码字折叠 Message-ID header ,但 MS 通过向收件人发送无意义的错误而不是在接收时拒绝邮件来处理错误是非常糟糕的。
您可以设置替代项 email policy通过将 flask_mail.message_policy
模块设置为全局来使用 Flask-Mail,或者我们可以生成不同的消息 ID。
电子邮件策略仅在您使用 Python 3.3 或更高版本时可用,但它是处理折叠的策略对象,因此允许我们更改 Message-ID 和其他 RFC 5322 标识符 header 的处理方式。这是一个不会折叠 Message-ID header 的子类;该标准实际上允许单行最多 998 个字符,并且此子类仅针对此 header 使用该限制:
import flask_mail
from email.policy import EmailPolicy, SMTP
# Headers that contain msg-id values, RFC5322
MSG_ID_HEADERS = {'message-id', 'in-reply-to', 'references', 'resent-msg-id'}
class MsgIdExcemptPolicy(EmailPolicy):
def _fold(self, name, value, *args, **kwargs):
if (name.lower() in MSG_ID_HEADERS and
self.max_line_length < 998 and
self.max_line_length - len(name) - 2 < len(value)
):
# RFC 5322, section 2.1.1: "Each line of characters MUST be no
# more than 998 characters, and SHOULD be no more than 78
# characters, excluding the CRLF.". To avoid msg-id tokens from being folded
# by means of RFC2047, fold identifier lines to the max length instead.
return self.clone(max_line_length=998)._fold(name, value, *args, **kwargs)
return super()._fold(name, value, *args, **kwargs)
flask_mail.message_policy = MsgIdExcemptPolicy() + SMTP
在 Python 2.7 或 Python 3.2 或更早版本上,您将不得不求助于替换 Message-Id header ,只需使用硬编码域名重新生成 header :
from flask import current_app
from flask_mail import Message as _Message
# set this to your actual domain name
DOMAIN_NAME = 'example.com'
class Message(_Message):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# work around issues with Microsoft Office365 / Outlook.com email servers
# and their inability to handle RFC2047 encoded Message-Id headers. The
# Python email package only uses RFC2047 when encoding *long* message ids,
# and those happen all the time on Heroku, where the hostname includes a
# full UUID as well as 5 more components, e.g.
# aaf39fce-569e-473a-9453-6862595bd8da.prvt.dyno.rt.heroku.com
# The work-around is to just use our own domain name, hard-coded, but only
# when the message-id length exceeds 77 characters (MIME allows 78, but one
# is used for a leading space)
if len(self.msgId) > 77:
domain = current_app.config.get('MESSAGE_ID_DOMAIN', DOMAIN_NAME)
self.msgId = make_msgid(domain=domain)
然后您将使用上面的 Message
类而不是 flask_mail.Message()
类,它会生成一个更短的 Message-ID header ,不会不会与 Microsoft 有问题的 header 解析器发生冲突。
我提交了 a bug report with the Python project跟踪 msg-id token 的处理,因为我怀疑这真的应该在那里解决。
关于python - Flask 邮件安全不符合 Microsoft Outlook 的安全要求?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52708969/
我正在尝试将 Outlook API 与我的 React 应用程序集成。当我尝试使用 microsoft-graph-client 实现身份验证时,遇到以下错误。 'ImplicitMSALAuthe
我正在尝试使用 Microsoft Graph Beta API 在 Microsoft Teams 中创建 channel 。在文档中,它说 channel 实体具有属性 IsFavoriteByD
我的目标很简单。我想使用图形 API 将自动聊天消息发送到 MS Teams channel 。 这似乎是图形 API 的测试版功能,仅在 Microsoft.Graph.Beta 中可用。 我已经阅
通过委派权限获取 Teams channel 消息时(用户是团队成员): https://graph.microsoft.com/beta/teams/ {team_id}/channels/{cha
我正在使用带有 OData 端点的 Web API 和 Entity Framework 创建一个 RESTful 服务。 Microsoft.AspNet.WebApi.OData 和 Micros
我可以通过对标题和作者姓名的评估查询(以及解释查询)获得良好的结果。 但是如果我想通过 DOI 查找论文怎么办? 我可以通过扩展元数据描述(在现有搜索的属性中)获取条目的DOI信息,但是由于扩展元数据
我正在尝试通过displayName查询用户,但是在同时使用C#SDK和Graph Explorer发送请求时,我无法转义单引号。 更新:在示例中不清楚,我遇到麻烦的搜索词是I' 查询示例: http
我在使用 Microsoft fakes 的解决方案中有一个单元测试项目,当我构建它时出现以下错误。它提示无法加载的 DLL 在磁盘上。我已经打开了 Fusion 日志记录,这表明绑定(bind)成功
我想创建一个应用程序,当用户在 MS Teams 中接到电话时会收到通知。我的意思是我想在来电事件上订阅一些东西,然后根据来电信息做一些事情。这可能吗?到目前为止,我在 SDK 中没有看到任何事件。
如果我开发一个网站,它是否会以相同的方式在 IE11、Chrome、Firefox 和 edge 上运行,还是我们需要专门为 IE11 编写代码?我没有 Windows 8,因此无法在边缘浏览器上测试
我几个月前为某些收件箱创建了一些订阅,系统成功收到了有关收到电子邮件的通知,订阅也定期更新以增加到期日期。这是我的订阅列表: https://graph.microsoft.com/v1.0/subs
如果我开发一个网站,它是否会以相同的方式在 IE11、Chrome、Firefox 和 edge 上运行,还是我们需要专门为 IE11 编写代码?我没有 Windows 8,因此无法在边缘浏览器上测试
如果 Edge 在某些机器上发生崩溃,我们需要检查日志以了解发生了什么情况。 最佳答案 Microsoft Edge 实际上是一个 Windows 进程,因此您应该能够在事件查看器中查看日志。此外,您
我已经将一些测试用例与项目中的单元测试相关联。该项目已构建并复制到共享上的放置位置。当我去运行这些测试时,由于作为这些测试的一部分包含的非托管 DLL 的 System.DllNotFoundExce
我对 asp.net 核心标识中的三个包感到困惑。我不知道彼此之间有什么区别。还有哪些是我们应该使用的? 我在 GitHub 上找到了这个链接,但我没有找到。 Difference between M
在我的 Windows 类库(由 MVC 网站使用)中,我安装了 NugetPackage Microsoft.SqlServer.Types (Spatial)。 现在,我正在使用 ado.net
我有一个简单的 web 应用程序,我在 Teams 中显示为一个应用程序。我已经在 App Studio 中进行了设置,一切都按我的预期工作,一切都很好。它正在显示我的网络应用程序,这就是我想要的。
有什么不同?它们都是业务管理解决方案。他们做的一样吗?一些不同的版本?他们使用同一个平台吗? 动态 Assets 净值 Microsoft Dynamics NAV 2009 is a compreh
如何制定包含非英语字符(例如日耳曼语Umlauts)的Microsoft Graph /myOrganization/users OData查询? 例子: 我的租户中有一个名为“ThomasMülle
我想创建一个类似于乐队附带的星巴克应用程序的应用程序。我想显示条形码。我可以在云端或本地设备上将条形码生成为 JPG 图像,但我需要能够在乐队的屏幕上显示它们。到目前为止,我还没有找到使用 Band
我是一名优秀的程序员,十分优秀!