Postfix 中继:仅根据特定标准将消息发送到互联网,如果不符合标准,则中继到另一个中继

Postfix 中继:仅根据特定标准将消息发送到互联网,如果不符合标准,则中继到另一个中继

这听起来有点复杂,但我们有一个非常目前在我的一个客户的环境中针对电子邮件进行了邪恶的设置。

从最内层系统到外部,我们有:

Exchange Server -> Sendmail Server -> McAfee Email Gateway -> OUTSIDE

这有点邪恶,因为外部目的地的“外出”电子邮件(从系统内部人员发送到外部)不起作用,它们似乎被 McAfee 电子邮件网关捕获并且不会被中继到外部。

我想要做的是将 Postfix 服务器设置为中继和 SMTP 服务器,并且根据接收的内容执行以下任一操作:

  1. 直接发送电子邮件(使用 SMTP,仅用于外出回复)
  2. 将邮件中继到 Sendmail 服务器,并像平常一样执行其余的中继任务。

这看起来有点像下面这样:

Exchange Server -> Postfix Relay --- Out of Office messages only ---> OUTSIDE
                         |
                   All other mail
                         |
                         ---> Sendmail Server/Relay ---> McAfee Email Gateway ---> OUTSIDE

我有点搞不懂如何配置 Postfix 的选择性中继选项。有谁能告诉我如何实现这一点吗?

答案1

我想到了一个非常黑客的方法来解决这个问题。

本质上,我在 Postfix 服务器和 Exchange 服务器之间运行了一个用 Python 编写的定制 SMTP“服务器”,它实际上处理真实的中继路由。它用 Python 编写,并以超级用户身份在端口 25 上运行(因为端口绑定限制)。

然后,该 Python 脚本将像平常一样处理该消息,通过字符串解析器运行电子邮件,然后读取主题行以确定将其发送到何处,然后将原始消息不加修改地发送到本地 Postfix SMTP 服务器(直接发送到出站),或发送到网络上的其他中继。到目前为止,它似乎正在工作。

这是我在 Python 方面使用的代码:

#!/usr/bin/env python3

# Libraries
import smtplib
import smtpd
import asyncore
import email
import sys
from datetime import datetime

print('Starting custom mail handling server...')

# CONFIGURATION VARIABLES - We are expecting to relay, so... let's relay.
SMTP_RELAY = 'SMTP_RELAY_HOSTNAME_OR_IP'
SMTP_DIRECT = 'localhost'

#############
#############
# SMTP SERVER
#############
#############


# noinspection PyMissingTypeHints,PyBroadException
class AutoReplyHandlerSMTP(smtpd.SMTPServer):

    def process_message(self, peer, mailfrom, rcpttos, data, **kwargs):
        print('MESSAGE RECEIVED - [%s]' % datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
        print('Receiving message from:', peer)
        print('Message addressed from:', mailfrom)
        print('Message addressed to  :', rcpttos)
        print('Message length        :', len(data))
        print(data)

        # Flush the output buffered (handy with the nohup launch)
        sys.stdout.flush()

        # Analyze and extract data headers
        msg = email.message_from_string(data)
        subject = ''
        try:
            subject = msg['Subject']
            subject = subject.lower()
        except:
            print("Subject error:", sys.exc_info()[0])
        print('Message subject       :', msg['Subject'])

        # Determine whether we are directly sending outbound, or if we're relaying to another server.
        if "automatic reply" in subject:
            print("Automatic reply received, sending directly.")
            # Local postfix SMTPd is on tcp/6625.
            conn = smtplib.SMTP(host=SMTP_DIRECT, port=6625, timeout=60)
            conn.sendmail(mailfrom, rcpttos, msg.as_string())
            conn.quit()
        else:
            print("Standard message detected, sending to relay.")
            # Other relay server is on tcp/25 (standard smtp)
            conn = smtplib.SMTP(host=SMTP_RELAY, timeout=60)
            conn.sendmail(mailfrom, rcpttos, msg.as_string())

        # Flush the output buffered (handy with the nohup launch)
        print("\n\n")
        sys.stdout.flush()
        return


# Listen to port 25 ( 0.0.0.0 can be replaced by the ip of your server but that will work with 0.0.0.0 )
server = AutoReplyHandlerSMTP(('0.0.0.0', 25), None)

# Wait for incoming emails
asyncore.loop()

我将 Postfix 配置为在不同端口上监听 SMTP。实际上,这就是最终在/etc/postfix/master.cf我的 Ubuntu 服务器上完成的操作,最终就是这两行以及我在 Postfix 中配置 SMTPd 的方式 - 请注意,您可以将任何高编号端口用作 Postfix SMTPd 的任何其他端口,但我选择了一些简单的东西:

#smtp      inet  n       -       y       -       -       smtpd
6625      inet  n       -       y       -       -       smtpd

然后,Python 脚本将数据转发到端口6625,Postfix 的 SMTPd 在那里运行;完成此操作后,我们专门让 Python 确定哪个 SMTP 服务器或中继是“下一跳”。这有点破坏了标准的“接收者”标头,但它应该可以很好地处理消息。

我的解决方案没有遇到任何问题,而且似乎可以正常工作。需要进行额外的测试,但这个“解决方案”似乎解决了如何路由消息(直接通过 SMTP 发送,或通过其余中继)的路由问题,而实际上不会干扰 Postfix 配置。

相关内容