如何解决Odoo无法发送Email的问题

经常有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)的形式出现。包括一些必须的信息比如: FROMTODATE 等以及 其他的常见头信息比如: SUBJECT, CC 等。另外还包括比如邮件代理发送时间戳,接收时间戳 ,及其他的自定义信息。当我们查看邮件的源码时,就能看到所有的头信息了,比如:

邮件头信息例子

Return-Path: <[email protected]>
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 [email protected]; Mon, 23 Aug 2004 11:40:10 -0400
Message-ID: <[email protected]>
Date: Mon, 23 Aug 2005 11:40:36 -0400
From: Taylor Evans <[email protected]>
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 <[email protected]>
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 [email protected]; 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 [email protected]; 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机制的邮件通讯的差别: 比如: [email protected] 这个用户不存在,那么邮件发送时,邮件退回时的差别如下:

邮件列表管理者无法直接从退回的邮件中了解问题接受者的信息。 而VERP通过下面的办法解决了这个问题:

注意上面这个根据每个不同接受者动态构建的Envelope Return Path: postmaster+bob=[email protected] 从这个地址中我们就能直接分析出:[email protected] 是问题接收者,从而可以自动化的采取措施停止发送邮件给该用户。

VERP确实对甄别问题发送者很有帮助,但是也有弊端,比如发送效率的问题。对 于多个同一域名下的邮件用户,不使用VERP可以一次成批发送,而因为要为每个接收用户分 别构造VERP, 所以只能一封一封的发送。

另外,VERP还可以用于邮件的信息关联跟踪,Odoo中就 是这样来使用VERP的,Odoo中的VERP有类似: [email protected] 的形式。

Odoo中的邮件处理

Odoo是以VERP作为Sender来发送邮件的,并且邮件的From头信息也是因关联用户的邮件的邮件的,所以无论是Sender还是邮件头的From都可能与SMTP服务器的认证用户的邮件不同,所以当SMTP服务器不支持邮件Relay时就无法发送邮件了。知道这个原理,我们只要将odoo/odoo/addons/base/ir/ir_mailserver.pysend_email函数改造一下,使其使用SMTP认证用户发送而非VERP就可以解决邮件发送问题了。