在 Postfix 上做 SMTP 中继,并隐藏原邮件服务器,再部署 SSL 证书;hMailServer 上使用 VBScript 根据发件人域来选择不同的 SMTP 中继服务器

一 、Postfix :

当前 CentOS Linux 的版本号为:

[root@host ~]# cat /etc/redhat-release 
CentOS Linux release 8.1.1911 (Core) 
[root@host ~]#

Postfix 使用 yum 源来安装:

[root@host ~]# yum -y install postfix

当前安装的 Postfix 版本如下所示:

[root@host ~]# rpm -qa | grep postfix
postfix-3.3.1-9.el8.x86_64
[root@host ~]#

我们现在假设有一台邮件服务器 1.1.1.1 ,以及一个配置在邮件服务器 1.1.1.1 上的邮件域名:@test.com ,还有一台即将配置 SMTP 中继的服务器 2.2.2.2 。现在我们要达成的目标是:

  1. 原本发往 @test.com 的邮件是直接发送到 1.1.1.1 的,现在要求发往 @test.com 的邮件先到达 SMTP 中继服务器 2.2.2.2 ,再由 2.2.2.2 转往 1.1.1.1 ;
  2. 从 1.1.1.1 发送出去的邮件原本是直接发送给目标邮件服务器的(如 @qq.com ),现在从 1.1.1.1 发送出去的邮件先发送给 2.2.2.2 ,2.2.2.2 再转发给目标邮件服务器(如 @qq.com )。

这里需要注意的是,本文只说明 Postfix 和 hMailServer 的相关配置,而 DNS 的配置是非常简单的,您只需要将 test.com 的 MX 记录从 1.1.1.1 改为 2.2.2.2 即可,在此不做过多赘述( Ricky 是这么想的,您都有一个现成的邮箱服务器了,怎么可能不会配置 DNS 呢?)。

在对 Postfix 的配置文件做修改前,我们先来看看 Postfix 默认中继邮件的方式:

# By default, Postfix relays mail
# - from "trusted" clients (IP address matches $mynetworks) to any destination,
# - from "untrusted" clients to destinations that match $relay_domains or
#   subdomains thereof, except addresses with sender-specified routing.

默认情况下,Postfix 中继邮件的方式:

  • 从 “ 受信任 ” 客户端( IP 地址与 $mynetworks 匹配)到任何目标,
  • 从 “ 不受信任 ” 客户端到与 $relay_domains 或其子域匹配的目标,具有发件人指定路由的地址除外。

现在我们在 Postfix 的默认配置文件 /etc/postfix/main.cf 上做相应的修改。

1 、修改 mynetworks :

Postfix 根据 mynetworks 的值来区别用户是远程的还是本地的。

将:

#mynetworks = 168.100.189.0/28, 127.0.0.0/8

改为:

mynetworks = 1.1.1.1/32, 2.2.2.2/32, 127.0.0.0/8

2 、修改 mydestination 和 relay_domains :

mydestination 表示 Postfix 要接收哪些域名的邮件,不在此区域内的都算是中继邮件。

relay_domains 表示可转发的邮件域名。

将:

mydestination = $myhostname, localhost.$mydomain, localhost
#relay_domains = $mydestination

改为:

mydestination =
relay_domains = test.com

只有当 “ mydestination = ” 时,从外部邮箱(如 @qq.com )往 @test.com 发送邮件,邮箱服务器 1.1.1.1 才能收到邮件。否则邮件会被 SMTP 中继服务器 2.2.2.2 退信:

550 5.1.1 : Recipient address rejected: User unknown in local recipient table (in reply to RCPT TO command)

大概意思就是 2.2.2.2 上的 Postfix 会去查这个邮箱地址为 xxx@test.com 的收件人是否存在(这个邮箱地址是注册在 1.1.1.1 上的,而不是在 2.2.2.2 上的,2.2.2.2 肯定找不到,于是 2.2.2.2 就 rejected 了),而不是将这封邮件直接转发给 1.1.1.1 。

Ricky 在这个坑里蹲了好久,直到在 Postfix 官网上看到一个例子:

Postfix 官网上的一个例子
Postfix 官网上的一个例子
Line 6: Disable local mail delivery. All mail goes to the mail server as specified in line 4.

翻译过来就是:

第 6 行:禁用本地邮件传递。所有邮件都将按照第 4 行中的指定发送到邮件服务器。

3 、修改 inet_interfaces :

inet_interfaces 表示 Postfix 监听的 IP 地址,Postfix 默认工作在 127.0.0.1 上。

将:

inet_interfaces = localhost

修改为:

inet_interfaces = 2.2.2.2

或者修改为:

inet_interfaces = all

4 、添加 transport_maps :

Postfix 接收到 @test.com 的邮件后,需要知道这个邮件转发到哪里,所以我们需要在 main.cf 中添加如下配置:

transport_maps = hash:/etc/postfix/transport

再在文件 /etc/postfix/transport 的最后一行添加 “ test.com  relay:[mail1.test.com] ” :

[root@host ~]# echo "test.com  relay:[mail1.test.com]" >> /etc/postfix/transport

其中 DNS 域名 mail1.test.com( A 记录即可)是指向邮件服务器 1.1.1.1 的。

最后使用 postmap 命令生成 transport 对应的数据库文件 transport.db :

[root@host ~]# postmap /etc/postfix/transport

切勿在 main.cf 中配置 relayhost 这个参数,配置 relayhost 后,需要中继的邮件默认都会往 relayhost 转发。如果我们在 main.cf 中这么配置(且没有配置 transport_maps ):

relayhost = mail1.test.com

那么在邮件服务器 1.1.1.1 中发送一封邮件,如从 @test.com 发往 @qq.com ,这封邮件到达 SMTP 中继服务器 2.2.2.2 后,2.2.2.2 不会将这封邮件转发到 QQ 的邮件服务器,而是会将这封邮件重新转发回 1.1.1.1 。没错,这个坑 Ricky 也踩过,因为需要中继的邮件默认都会往 relayhost 转发,我们不需要这种默认转发的机制。

5 、在邮件中隐藏邮件服务器 1.1.1.1 :

真正跟外界通讯的服务器应该是 SMTP 中继服务器 2.2.2.2 ,邮件服务器 1.1.1.1 按理来说是不会暴露到互联网上去的,但事实并非如此。如果我们在邮件服务器 1.1.1.1 中发送一封邮件,如从 @test.com 发往 @qq.com(不一定非得发往 @qq.com ,其他第三方邮箱也可),然后您去 QQ 邮箱中查看原始的邮件内容,您会发现这么两个头部:

Received: from 2.2.2.2  # 这是 QQ 邮箱服务器加上去的
......
Received: from 1.1.1.1  # 这是 SMTP 中继服务器 2.2.2.2 加上去的
......

如果您对邮件的工作方式有所了解,您会知道第二个 Received 头部是由 Postfix 加上去的,如何从 Postfix 生成的邮件头部中删除客户端发送者 IP( X-Originating-IP )呢(亦即删除多余 Received 头部)?

在 main.cf 中找到下面这一行,将:

#header_checks = regexp:/etc/postfix/header_checks

修改为:

header_checks = regexp:/etc/postfix/header_checks

同时我们在文件 /etc/postfix/header_checks 的最后一行添加 “ /^Received:/ IGNORE ” :

[root@host ~]# echo "/^Received:/ IGNORE" >> /etc/postfix/header_checks

这样,Postfix 就不会添加 Received 头部了。当然,很多头部我们都是可以去除的:

[root@host ~]# echo "/^X-Originating-IP:/ IGNORE" >> /etc/postfix/header_checks
[root@host ~]# echo "/^X-Mailer:/ IGNORE" >> /etc/postfix/header_checks
[root@host ~]# echo "/^User-Agent:/ IGNORE" >> /etc/postfix/header_checks

6 、在 Postfix 中配置 SSL 证书:

在 main.cf 中添加或修改如下配置:

smtpd_tls_security_level = may
smtpd_tls_key_file = /etc/pki/tls/certs/private.key
smtpd_tls_cert_file = /etc/pki/tls/certs/cert.pem

key file 和 cert file 为 SSL 证书的相关文件,如果您想了解如何自动化申请和更新 https 证书( SSL 证书),请点击这里

然后我们到 /etc/postfix/master.cf 中将:

#smtps     inet  n       -       n       -       -       smtpd

修改为:

smtps     inet  n       -       n       -       -       smtpd -o smtpd_tls_wrappermode=yes

即可。

7 、启动 Postfix 服务:

现在我们可以启动 Postfix 服务了:

[root@host ~]# systemctl start postfix

我们可以看到 SMTP 的端口(默认是 25 号端口,465 号端口是用于 SSL/TLS 加密的)已经起来了:

[root@host ~]# netstat -ntlp | grep -E "25|465"
tcp        0      0 2.2.2.2:465      0.0.0.0:*               LISTEN      29782/master
tcp        0      0 2.2.2.2:25       0.0.0.0:*               LISTEN      29782/master
[root@host ~]#

Postfix 的配置到这里就结束了。

二 、hMailServer :

Ricky 将以邮箱服务器 1.1.1.1 上安装的是 hMailServer 为例,说说在邮箱服务器 1.1.1.1 上该如何配置。

1 、Incoming relay :

进入 hMailServer 的管理后台,首先我们可以配置一个 Incoming relay(传入中继),具体如下图所示:

hMailServer - Incoming relay
hMailServer – Incoming relay

如需查看 Incoming relay 的官方文档,请点击这里

2 、IP range :

同时最好在 IP ranges 中添加这台 SMTP 中继服务器,在 General 的配置中,优先级( Priority )最好大于 20 。因为自动屏蔽( Auto-ban )的 IP range 的优先级是 20 , 而优先级越大,策略就会最先执行。具体如下图所示:

hMailServer - IP range - General
hMailServer – IP range – General

在 Allow connections 的配置中,只需要选择 SMTP 即可。因为 Postfix 只工作在 SMTP 协议上,POP3 和 IMAP 协议都用不上。具体如下图所示:

hMailServer - IP range - Allow connections
hMailServer – IP range – Allow connections

在 Allow deliveries from 的配置中,External to external e-mail addresses(外部邮件地址到外部邮件地址)就不用勾选了。当前 hMailServer 上配置的邮箱域名(如 @test.com )就是本地邮件地址( local e-mail addresses ),@qq.com 和 @sina.com 这些就是外部邮件地址,我们不需要帮助这些外部邮箱来传送邮件。具体如下图所示:

hMailServer - IP range - Allow deliveries from
hMailServer – IP range – Allow deliveries from

在 Require SMTP authentication 的配置中,External to local e-mail addresses 就不用勾选了。如果外部邮件地址把邮件发送到本地邮件地址还需要做 SMTP 验证,那么外部邮件地址(如 @qq.com )就没法向 @test.com 发送邮件了,因为做 SMTP 验证是需要账号和密码的,第三方邮箱服务器可不知道这些账号和密码(特殊需求除外)。具体如下图所示:

hMailServer - IP range - Require SMTP authentication
hMailServer – IP range – Require SMTP authentication

那什么时候需要使用 SMTP 验证呢?Ricky 这里简单解释一下,假设我们有一个用户叫做 xxx@test.com ,如果这个用户想发送邮件,他是不是要登录相关的邮箱系统(如:https://ccie.lol/mail )才能发送邮件?登录邮箱系统是不是需要相关的账号和密码?此时这个账号和密码就是拿来做 SMTP 验证的。

那为什么 External to external e-mail addresses(外部邮件地址到外部邮件地址)需要做 SMTP 验证呢?如上文所述,我们不需要帮助这些外部邮箱来传送邮件,所以这里可以故意加一个 SMTP 验证,不让外部的系统或人员登录进来。

在 Other 的配置中,需不需要( Anti-spam )反垃圾和( Anti-virus )反病毒的功能看您的需求(这两个功能是需要第三方软件支持的,hMailServer 本身不提供相关功能,这里就不赘述了),在做验证时是否需要使用 SSL/TLS 加密也是看您的需求。具体如下图所示:

hMailServer - IP range - Other
hMailServer – IP range – Other

3 、SMTP 中继(全局):

上述两个配置其实都是可选配置,即你不配置问题似乎也不大,而现在这个配置是必须要配置的了,即配置 SMTP 中继服务器( SMTP relayer )。如果不需要做验证( Server requires authentication ),那么如下图所示这样配置即可:

hMailServer - SMTP - Delivery-of e-mail
hMailServer – SMTP – Delivery-of e-mail

这里需要注意的是:

  • 这里设置的 Local host name 应当在 Postfix 的 $mynetworks 中;
  • 而且这个 SMTP relayer 是全局配置,当前 hMailServer 中的所有域( Domains ,如 @test.com )都会通过这个 SMTP relayer 进行中继。

4 、SMTP 中继(基于收件人域):

如果您希望根据不同的收件人域( Recipient’s domain )来选择不同的 SMTP 中继服务器,可使用 SMTP 路由( Route ),具体如下图所示:

hMailServer - SMTP - Route
hMailServer – SMTP – Route

在 SMTP 路由( Route )中会设置 Domain 、Target SMTP host 和 TCP/IP port ,如果我们配置了两个 SMTP 路由( Route ):

Domain = qq.com
Target SMTP host = 2.2.2.2
TCP/IP port = 25

Domain = sina.com
Target SMTP host = 3.3.3.3
TCP/IP port = 25

就意味着当邮件发往 @qq.com(即收件人域是 @qq.com )时,会使用 2.2.2.2:25 这台 SMTP 中继服务器;而当邮件发往 @sina.com(即收件人域是 @sina.com )时,会使用 3.3.3.3:25 这台 SMTP 中继服务器。

如需查看 Route 的官方文档,请点击这里

5 、SMTP 中继( Rule and Route ):

在 hMailServer 的论坛里,你经常能看到这种 Rule and Route(规则和 SMTP 路由)的配置方式,如《 How to rule and route? 》,具体如下图所示:

hMailServer - SMTP - Rule and Route
hMailServer – SMTP – Rule and Route

即先创建一个 Rule(规则),当发送的邮件的 From 字段(即发件人邮箱地址)包含(注意应使用 Contains 而不能使用 Equals )qq.com 时,则该邮件使用选定的 SMTP 路由进行发送( Send using route )。

Ricky 感觉这个功能好像没什么用,因为在使用选定的 SMTP 路由进行发送时,Route 中的 Domain 也是要匹配的,不是说发件人邮箱地址匹配上了就一定会将邮件发送到选定的 Route 中的 Target SMTP host 。

如果我的想法是错的,欢迎在下方留言(注:Ricky 当前使用的 hMailServer 版本为 5.6.7 – Build 2425 )。

如需查看 Rule 的官方文档,请点击这里

6 、SMTP 中继(使用 VBScript 根据发件人域来选择不同的 SMTP 中继服务器):

发件人域( Sender’s domain )如 @test.com ,与收件人域类似。我们如何根据不同的发件人域来选择不同的 SMTP 中继服务器呢?Ricky 在逛 hMailServer 论坛时看到两个贴子,深受启发,一个是《 Different sender based SMTP route for outgoing emails 》:

Re: Different sender based SMTP route for outgoing emails
Quote
Post by ^DooM^ » 2011-06-06 11:38

You cannot do this with a standard hMail install, what you could possibly do is use the ComAPI to read the sender domain from the connecting client and if it matches one of your senders, update the SMTP relayer fields, using hMails onaccept event.

The only problem I see with doing that is if you send multiple emails at the same time to different domains that require multiple SMTP relayer settings, it could end up being relayed through a different server than intended due to hMails multi threaded nature.

上面这位大佬给出了使用 VBScript 脚本来解决这个问题的可能性,当然第二段也说明了这个方法存在的问题。这位大佬其实就是说,通过往 hMailServer 挂一个 VBScript 脚本来处理这个问题:当邮件发送时读取发件人域,然后根据发件人域立马设置对应的 SMTP 中继服务器(注意这可是全局配置)。如果同时发送好几封邮件( hMailServer 是多线程的),那么就会同时修改这个全局配置,那么此时就会错乱。

另一个是《 Dynamic SMTP Relay 》,这个帖子给出了一个 VBScript 脚本示例,Ricky 将在该 VBScript 脚本示例的基础上进行改进:

Re: Dynamic SMTP Relay
Quote
Post by prashanthRaju » 2019-03-11 21:01

The test code works! I need to change the global SMTP relay settings for each message to ensure that the relay account of the sender is used for sending the message.
I understand that I should be doing this not in OnAcceptMessage because outgoing messages would be queued, but which of these two delivery events – OnDeliveryStart or OnDeliveryMessage should I be targeting? Any idea what’s the difference between them? The documentation isn’t too clear on this.
Thanks!

Sub OnAcceptMessage(oClient, oMessage)
On Error Resume Next
If oClient.UserName <> "" THEN
Dim setting_username, setting_password
Dim obApp
Dim userpassword
Dim oSettings
Set obApp = CreateObject("hMailServer.Application")
Call obApp.Authenticate(setting_username, setting_password)

Set oSettings=  obApp.Settings
oSettings.SMTPRelayer = "relayserver.net"
oSettings.SMTPRelayerPort=465
oSettings.SMTPRelayerRequiresAuthentication=true
oSettings.SMTPRelayerUsername = oMessage.fromAddress
oSettings.SMTPRelayerUseSSL=true
userpassword = "password" 'get the password from your db, or wherever
oSettings.SetSMTPRelayerPassword("password")

End If
End Sub

如需查看 COM API 中 Settings object 的官方文档,请点击这里

Ricky 先来说说 Ricky 这边的背景,Ricky 现在有一台 hMailServer 邮件服务器,这台邮件服务器拥有多个邮箱域名:@test.com 、@test.org 和 @test.net ,而只有 @test.com 才需要做 SMTP 中继。大体的思路是:

  • 如果发件人域是 @test.com ,我们先看这封邮件的收件人(可能存在多个收件人)是否是本地用户( 即本地邮件地址,local e-mail addresses )。如果收件人都是本地用户,那么我们并不需要关心是否配置了 SMTP 中继;如果收件人中存在至少一位非本地用户(即外部邮件地址,external e-mail addresses ),那么就需要配置 SMTP 中继了。
  • 如果发件人域是 @test.org 和 @test.net ,自然不需要配置 SMTP 中继。

为了实现上述功能,首先 Ricky 会创建一个文件,该文件相当于锁:

  1. 该文件的第一行用来存储锁的状态(有两种状态:Direct 和 Relay ),
  2. 该文件的第二行用来存储当前锁创建的时间。

如果发件人域 @test.com 发送了一封邮件,那么这个锁就会被创建或者重写(锁将处于 Relay 状态):

  1. 在这个锁创建的第 120 秒内,如果发件人域 @test.com 又发送了一封邮件,那么锁的创建时间将会被刷新;
  2. 在这个锁创建的第 120 秒内,如果发件人域 @test.org 或 @test.net 发送了一封邮件呢?那么这封邮件的发送将会失败,Ricky 这边使用的 WebMail 是 Roundcube Webmail ,Roundcube Webmail 此时会返回如下错误信息(注意:这个错误信息是由 VBScript 脚本自定义的):
Roundcube Webmail 此时会返回如下错误信息
Roundcube Webmail 此时会返回如下错误信息

反过来也是一样的,如果发件人域 @test.org 或 @test.net 发送了一封邮件,那么这个锁就会被创建或者重写(锁将处于 Direct 状态):

  1. 在这个锁创建的第 120 秒内,如果发件人域 @test.org 或 @test.net 又发送了一封邮件,那么锁的创建时间将会被刷新;
  2. 在这个锁创建的第 120 秒内,如果发件人域 @test.com 发送了一封邮件呢?那么这封邮件的发送将会失败。

那为什么需要 “ 锁住 ” 这 120 秒的时间呢?就是为了让邮件在这段时间内发送出去,防止出现错乱(当然,Ricky 这边的邮箱用户比较少,所以才会这么做,您也可以自己实现一个更符合自身需求的策略)。

本来 Ricky 是想在邮件发送成功后,就把锁删除掉,但 Ricky 发现 hMailServer 有 OnDeliveryStart 事件、OnDeliveryFailed 事件和 OnAcceptMessage 事件,却没有邮件发送成功后调用的事件,所以只好退而求其次采用了上述方法。

这个 VBScript 脚本 Ricky 将会采用面向过程的方式来开发,毕竟也没有几行。如果感觉很 Low ,还请见谅。

VBScript 脚本代码和您需要修改的变量,如下所示:

  • strLock :用来配置 “ 锁 ” 文件的路径,Ricky 这里是 E:\hMailServer\Events\SMTP_relayer_lock ;
  • strSMTPRelayer :SMTP 中继服务器的 IP 地址或者域名;
  • intDiffTime :上文提到的 120 秒的等待时间是可以做调整的,修改该变量即可;
  • 在调用 Call obApp.Authenticate(username, password) 这个方法时,需要填写登录 hMailServer 后台的账号和密码。
Const strLock = "E:\hMailServer\Events\SMTP_relayer_lock"
Const strSMTPRelayer = "mail1.test.com"
Const intDiffTime = 120
Dim objFSO:Set objFSO = CreateObject("Scripting.FileSystemObject")
Const ForReading = 1
Const ForWriting = 2
'Const ForAppending = 8

Sub SMTPRelayerSettings(strSMTPRelayer):
    Dim obApp:Set obApp = CreateObject("hMailServer.Application")
    Call obApp.Authenticate("administrator", "123456")  '登录 hMailServer 后台的账号和密码
    Dim oSettings:Set oSettings = obApp.Settings
    oSettings.SMTPRelayer = strSMTPRelayer
    oSettings.SMTPRelayerPort = 465
    oSettings.SMTPRelayerUseSSL = true  '使用 SSL
End Sub

Sub WriteLock(strLockState):
    On Error Resume Next
    Dim objLock:Set objLock = objFSO.OpenTextFile(strLock, ForWriting, True)
    objLock.WriteLine(strLockState)  '写入当前锁的状态
    objLock.WriteLine(Now())  '写入当前锁的创建时间
    objLock.Close
End Sub

Function ReadLock():
    On Error Resume Next
    Dim objDict:Set objDict = CreateObject("Scripting.Dictionary")
    Dim objLock:Set objLock = objFSO.OpenTextFile(strLock, ForReading)
    objDict("LockState") = objLock.ReadLine  '读取当前锁的状态
    objDict("LockDateCreated") = objLock.ReadLine  '读取当前锁的创建时间
    objLock.Close
    Set ReadLock = objDict
End Function

Sub OnAcceptMessage(oClient, oMessage)
Randomize
Dim upperbound:upperbound = 100000
Dim lowerbound:lowerbound = 100
Dim intRandom:intRandom = Int((upperbound - lowerbound + 1) * Rnd + lowerbound)
Dim strAddress
Dim strAddresses
Dim diff
If oClient.UserName <> "" Then
    On Error Resume Next
    EventLog.Write(oClient.UserName & " : " & intRandom & " : OnAcceptMessage Start ...")
    If InStr(1, oMessage.FromAddress, "@test.com", 1) > 0 Then  '如果当前发件人域是 @test.com
        '判断当前所有的收件人是否都是本地用户
        Dim isLocalUser:isLocalUser = True
	strAddresses = ""
        For i = 0 To oMessage.Recipients.Count - 1
	    strAddress = oMessage.Recipients.Item(i).Address  '使用 oMessage.Recipients.Item(i).IsLocalUser 不太准确
	    If strAddresses = "" Then
		strAddresses = strAddress
	    Else
		strAddresses = strAddresses & ", " & strAddress
	    End If
	    Dim isLocalUserTemp:isLocalUserTemp = False
            If InStr(1, strAddress, "@test.com", 1) > 0 Then
                isLocalUserTemp = True
	    ElseIf InStr(1, strAddress, "@test.net", 1) > 0 Then
		isLocalUserTemp = True
	    ElseIf InStr(1, strAddress, "@test.org", 1) > 0 Then
		isLocalUserTemp = True
            End If
	    If isLocalUserTemp = False Then
		isLocalUser = False
	    End If
        Next
	EventLog.Write(oClient.UserName & " : " & intRandom & " : Recipients count = " & oMessage.Recipients.Count & ", All recipients = " & strAddresses)

        If isLocalUser Then  '如果所有的收件人都是本地用户,那么无所谓当前是否配置了 SMTP 中继
            EventLog.Write(oClient.UserName & " : " & intRandom & " : All recipients is local user, no matter if SMTP relayer is configured.")
        Else  '如果至少有一个收件人不是本地用户,那么需要设置 SMTP 中继并创建锁
            If objFSO.FileExists(strLock) Then  '如果存在锁
                Set objDict = ReadLock()
                strLockDateCreated = objDict.Item("LockDateCreated")
                If objDict.Item("LockState") = "Direct" Then  '如果当前处于 Direct 状态,那么检查这个锁存在的时间是否已经超过 intDiffTime 秒
                    diff = DateDiff("s", strLockDateCreated, Now())
                    If diff > intDiffTime Then  '如果这个锁存在的时间已经超过 intDiffTime 秒,那么重写锁,配置 SMTP 中继,并发送邮件
                        WriteLock("Relay")  '重写锁
			SMTPRelayerSettings(strSMTPRelayer)  '配置 SMTP 中继
                        EventLog.Write(oClient.UserName & " : " & intRandom & " : Diff > " & intDiffTime & ", At least one external user in all recipients! Lock time = " & strLockDateCreated & ", diff = " & diff)
                    Else  '如果这个锁存在的时间没有超过 intDiffTime 秒,那就让邮件发送失败
                        EventLog.Write(oClient.UserName & " : " & intRandom & " : Diff < " & intDiffTime & "! Sending mail failed! Lock time = " & strLockDateCreated & ", diff = " & diff)
                        '设置邮件发送失败
                        Result.Message = "The system is busy, Please try again in " & intDiffTime - diff & " seconds."
                        Result.Value = 2
                    End If
                Else  '如果当前处于 Relay 状态,那么重写锁,并直接发送邮件
                        WriteLock("Relay")  '重写锁
                        EventLog.Write(oClient.UserName & " : " & intRandom & " : SMTP relayer Lock has been locked. Sending mail.")
                End If
            Else  '如果不存在锁,那么重写锁,配置 SMTP 中继,并发送邮件
                WriteLock("Relay")  '重写锁
                SMTPRelayerSettings(strSMTPRelayer)  '配置 SMTP 中继
                EventLog.Write(oClient.UserName & " : " & intRandom & " : SMTP relayer Lock Not Found, and SMTP relayer Lock is Locked! At least one external user in all recipients! Sending mail.")
            End If
        End If
    Else  '如果当前发件人域不是 @test.com
        If objFSO.FileExists(strLock) Then  '如果存在锁
            Set objDict = ReadLock()
            strLockDateCreated = objDict.Item("LockDateCreated")
            If objDict.Item("LockState") = "Relay" Then  '如果当前处于 Relay 状态,那么检查这个锁存在的时间是否已经超过 intDiffTime 秒
                diff = DateDiff("s", strLockDateCreated, Now())
                If diff > intDiffTime Then  '如果这个锁存在的时间已经超过 intDiffTime 秒,那么去除 SMTP 中继的配置,重写锁,并发送邮件
		    SMTPRelayerSettings("")  '去除 SMTP 中继的配置
                    WriteLock("Direct")  '重写锁
                    EventLog.Write(oClient.UserName & " : " & intRandom & " : Diff > " & intDiffTime & ", Lock time = " & strLockDateCreated & ", diff = " & diff)
                Else  '如果这个锁存在的时间没有超过 intDiffTime 秒,那就让邮件发送失败
                    EventLog.Write(oClient.UserName & " : " & intRandom & " : Diff < " & intDiffTime & "! Sending mail failed! Lock time = " & strLockDateCreated & ", diff = " & diff)
                    '设置邮件发送失败
		    Result.Message = "The system is busy, Please try again in " & intDiffTime - diff & " seconds."
		    Result.Value = 2
                End If
            Else  '如果当前处于 Direct 状态,那么重写锁,并直接发送邮件
                WriteLock("Direct")  '重写锁
                EventLog.Write(oClient.UserName & " : " & intRandom & " : SMTP relayer Lock has been locked. Sending mail.")
            End If
        Else  '如果不存在锁,那么重写锁,并直接发送邮件
            WriteLock("Direct")  '重写锁
            EventLog.Write(oClient.UserName & " : " & intRandom & " : SMTP relayer Lock Not Found. Sending mail.")
        End If
    End If
    EventLog.Write(oClient.UserName & " : " & intRandom & " : OnAcceptMessage End ...")
End If
End Sub

那如何将这个 VBScript 脚本应用到 hMailServer 中呢?

首先我们需要将上述 VBScript 脚本代码复制到 hMailServer 安装目录下的 Events\EventHandlers.vbs 中。然后我们需要进入 hMailServer 后台中关于 Scripts 的配置页面,在 General 中的 Enabled 后方打勾,并在下拉框中选择 “ VBScript ” ,然后点击 “ Save ” 按钮即可。具体如下图所示:

hMailServer - Scripts - General
hMailServer – Scripts – General

如果您修改了 Events\EventHandlers.vbs 脚本文件,那么需要在 Actions 中点击 “ Reload scripts ” 按钮,让 hMailServer 重新加载脚本到内存(为了更加快速地执行脚本,hMailServer 会在内存中保存一份脚本的副本)。如果您想检查 Events\EventHandlers.vbs 脚本文件是否存在语法错误,可以点击 “ Check syntax ” 按钮。具体如下图所示:

hMailServer - Scripts - Actions
hMailServer – Scripts – Actions

上述 VBScript 脚本或者文章如有不足之处,欢迎在下方留言指正,谢谢。

Was this article helpful?

Related Articles

Leave A Comment?

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据