经常有Odoo的用户反映所有的邮件设置都正确但就是没办法在Odoo中发送邮件。原因其实很 简单,就是用户的SMTP服务器不支持Email Relay。难道就没有办法了吗?答案当然是否定的。
国内的大多数主流Email企业邮箱提供商,比如网易,QQ,阿里都不支持Email Relay,而 Email Relay对于Email别名(Email Alias)和VERP(Variable Envelope Return Path)的支持都 是必须的。在被这些名词搞晕之前我们先来了解一下Email的结构。
邮件的组成
Email由3个部分构成:
-
信封(Envelope)
-
头信息(Headers)
-
消息体(Body)
头信息
信封对于邮件用户来说是不可见的,它是Email路由通讯的内部流程的一部分。消息体是我
们通常所见的邮件内容,而头信息则是邮件的神秘而有趣的部分。头信息是在消息体之上的
多行信息,以键值对(KEY:VALUE)的形式出现。包括一些必须的信息比如: FROM
,TO
,DATE
等以及
其他的常见头信息比如: SUBJECT
, CC
等。另外还包括比如邮件代理发送时间戳,接收时间戳
,及其他的自定义信息。当我们查看邮件的源码时,就能看到所有的头信息了,比如:
邮件头信息例子
Return-Path: <example_from@dc.edu> X-SpamCatcher-Score: 1 [X] Received: from [136.167.40.119] (HELO dc.edu) by fe3.dc.edu (CommuniGate Pro SMTP 4.1.8) with ESMTP-TLS id 61258719 for example_to@mail.dc.edu; Mon, 23 Aug 2004 11:40:10 -0400 Message-ID: <4129F3CA.2020509@dc.edu> Date: Mon, 23 Aug 2005 11:40:36 -0400 From: Taylor Evans <example_from@dc.edu> User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0 X-Accept-Language: en-us, en MIME-Version: 1.0 To: Jon Smith <example_to@mail.dc.edu> Subject: Business Development Meeting Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit
邮件头中的路由信息
有些邮件中包含了多个`Received`时间戳信息,比如:
Received: from tom.bath.dc.uk ([138.38.32.21] ident=yalrla9a1j69szla2ydr) by steve.wrath.dc.uk with esmtp (Exim 3.36 #2)id 19OjC3-00064B-00 for example_to@imaps.bath.dc.uk; Sat, 07 Jun 2005 20:17:35 +0100 Received: from write.example.com ([205.206.231.26]) by tom.wrath.dc.uk with esmtp id 19OjBy-0001lb-3V for example_to@bath.ac.uk; Sat, 07 Jun 2005 20:17:30 +0100 Received: from master.example.com (lists.example.com [205.206.231.19]) by write.example.com (Postfix) with QMQP id F11418F2C1; Sat, 7 Jun 2005 12:34:34 -0600 (MDT)
邮件是通过`邮件发送代理`(MTA)从一台电脑发送到另一台电脑的。每一次的转发都会在 Email中添加`Received`时间戳头信息。我们应该从下往上来读邮件的路由信息。
VERP (Variable envelope return path)
这个就属于对用户不可见的信封
信息了。当我们跟邮件发送服务器(SMTP)通讯时就要提
供 Envelope Return Path
信息,当邮件不能被成功发送,该邮件就会被退回到这个
Envelope Return Path所定义的邮件地址。而 VERP
就是动态变动的Envelope
Return Path
, 其设计的初衷是为了甄别哪些是不能被接收的邮件地址,从而停止向这些
邮件地址发送邮件。这种机制一般用于邮件列表。
下面比较具有VERP
和没有VERP
机制的邮件通讯的差别:
比如: bob@xxx.net
这个用户不存在,那么邮件发送时,邮件退回时的差别如下:
-
不具有VERP的邮件发送:
-
信封发送者(envelope sender):
postmaster@openerp.cn
-
接收者:
bob@xxx.net
-
-
不具有VERP的退回邮件信息:
-
信封发送者:空
-
接受者:
postmaster@openerp.cn
-
邮件列表管理者无法直接从退回的邮件中了解问题接受者的信息。
而VERP
通过下面的办法解决了这个问题:
-
具有`VERP`,邮件发送:
-
信封发送者(envelope sender):
postmaster+bob=xxx.net@openerp.cn
-
接受者:
bob@xxx.net
-
-
具有`VERP` 的退回邮件信息:
-
信封发送者: 空
-
接受者:
postmaster+bob=xxx.net@openerp.cn
-
注意上面这个根据每个不同接受者动态构建的Envelope Return Path: postmaster+bob=xxx.net@openerp.cn
从这个地址中我们就能直接分析出:bob@xxx.net
是问题接收者,从而可以自动化的采取措施停止发送邮件给该用户。
VERP
确实对甄别问题发送者很有帮助,但是也有弊端,比如发送效率的问题。对
于多个同一域名下的邮件用户,不使用VERP可以一次成批发送,而因为要为每个接收用户分
别构造VERP, 所以只能一封一封的发送。
另外,VERP
还可以用于邮件的信息关联跟踪,Odoo中就
是这样来使用VERP的,Odoo中的VERP有类似: bounce+259-res.partner-1848@openerp.cn
的形式。
Odoo中的邮件处理
Odoo是以VERP
作为Sender来发送邮件的,并且邮件的From
头信息也是因关联用户的邮件的邮件的,所以无论是Sender还是邮件头的From
都可能与SMTP服务器的认证用户的邮件不同,所以当SMTP服务器不支持邮件Relay时就无法发送邮件了。知道这个原理,我们只要将odoo/odoo/addons/base/ir/ir_mailserver.py
中send_email
函数改造一下,使其使用SMTP认证用户发送而非VERP
就可以解决邮件发送问题了。