队列优先级
Exchange 2013当中,微软增加了一个“优先队列”的功能,打开它时,被标记为高优先级的邮件会比一般邮件先传送,而被标记为低优先级的邮件则会比一般邮件后传送;开启该功能之后呢,分拣器和路由算法不会受到任何影响,仅仅只是传输服务会在每个投递队列里按照优先级排列邮件。
队列优先级的设置主要通过修改EdgeTransport.exe.config配置文件的键值的方式来进行,首先通过PriorityQueuingEnabled键值设置为True开启该功能,接着按照需要调整下表里的细节选项,调整完成之后需要重启传输服务生效(Restart-Service MSExchangeTransport)
参数 | 含义 |
PriorityQueuingEnabled | 设置为True开启此MBX上的队列优先级功能,默认为False,则下面所有的选项均不生效。 |
MaxHighPriorityMessageSize | 指定高优先级的邮件大小,超过该邮件大小的邮件将被视为是普通邮件。默认为250KB。输入值时,需要带上KB或者MB作为单位。该值应该小于Set-TransportConfig里的MaxSendMessageSize值。 |
LowPriorityDelayNotificationTimeout NormalPriorityDelayNotificationTimeout HighPriorityDelayNotificationTimeout | 根据邮件优先级来指定延迟发送状态通知(DSN)邮件的超时间隔,默认为低:8小时,普通:4小时,高优先级:30分钟。意思就是高优先级的邮件如果因为某些原因被延迟了也应该早点获得延迟状态的通知。值的格式为dd.hh:mm:ss |
LowPriorityMessageExpirationTimeout NormalPriorityMessageExpirationTimeout HighPriorityMessageExpirationTimeout | 指定传输服务尝试发送失败邮件的最长时间,如果超过这个时间,则会给发件人返回NDR。与上面一条类似,高优先级的邮件会获得一个更早的邮件无法送达(NDR)的通知。默认为低:2天,中:2天,高:8小时,值的格式与上一条相同 |
MaxPerDomainLowPriorityConnections MaxPerDomainNormalPriorityConnections MaxPerDomainHighPriorityConnections | 这些键可以指定传输服务与任一单个远程域可以建立的最大连接数。使用邮箱服务器上的传递队列和发送连接器建立传出到远程域的连接。默认为低:2,中:15,高:3。这三个键加起来的总值不能超过Set-TransportService上的MaxPerDomainOutboundConnections属性 |
从上面的描述里可以看到,EdgeTransport.exe.config与Set-TransportService里的参数是有一个相互影响关系的。Set-TrasportService命令里的关于邮件Delay和Expiration的设置,则直接就对应EdgeTransport.exe.config里关于Normal邮件优先级的设置。
禁用排队优先级时,将忽略 EdgeTransport.exe.config 配置文件中的所有排队优先级邮件限制。Set-TransportService cmdlet 中的所有邮件限制适用于经过邮箱服务器上传输服务的所有邮件。
启用排队优先级时,EdgeTransport.exe.config 配置文件中的排队优先级邮件限制将覆盖 Set-TransportService cmdlet 中对应的邮件限制。Set-TransportService cmdlet 中的其他所有邮件限制仍适用于经过邮箱服务器上传输服务的低优先级、普通优先级和高优先级邮件。
另外还有一个就是Set-Mailbox命令里的DowngradeHighPriorityMessagesEnabled参数,默认为False,设置为True的话,从该MBX服务器发送的任何高优先级的邮件将自动降级为普通优先级。
管理队列
在日常操作过程当中,有可能会碰到需要手动干预调整队列的情况。一部分操作可以通过Exchange队列管理器的UI界面来完成,EMS也提供了一些命令来让管理员可以完成更详细的针对队列的操作,接下来咱们一块看看。
查看并管理队列中的邮件
考虑这样一个场景,你突然发现队列中出现邮件堆积,而且堆积的数量并不减少,且当前服务器的负载并不高,你想搞清楚为何这些邮件会堆积在队里里面。于是你使用Get-Queue命令获取堆积的那个队列的信息,如下:
从这些信息里,可以看到是因为DNS查询失败引起的邮件堆积,这时候你就得查查服务器配置里的DNS解析、域控的DNS公网转发、公网上究竟有没有存在这个SMTP域名等等。
也有的时候会碰到以下这种报错:
"421 4.2.1 Unable to connect. Attempted failover to alternate host, but that did not succeed. Either there are no alternate hosts, or delivery failed to all alternate hosts."
这种报错就代表当前的发送连接器里的源服务器无法连接到NextHopDomain里的下一跳目标,这种情况得先从自身查起,检查自己这边儿的CAS(代理发送连接器的话)或者是MBX能否访问外网,或是能到达目标SMTP域邮件服务器的25端口等。查明自身这边儿没问题,才能有足够底气跟对方联系:“你们邮件服务器收不到咱们的邮件!赶紧看看是不是反压了/数据库挂了/断网了!”
接着可以使用Get-Message命令可以获取这些被卡住的队列中的每一封邮件的信息。
注意返回的邮件列表中,前面有一个Identity,通过这个Identity还可以继续用get-message命令获取更详细的信息。
与Exchange 2010不同的是,Exchange 2013使用更长的数字来标识队列内的邮件,队列中邮件的Identity里的ID号与该邮件本身的Message-ID属性没关系,MessageID属性将会伴随该邮件一起在公网上移动,哪怕到了目标服务器也不会被更改。
如果你想暂停这封邮件的传递,或者是一组邮件的传递,那么可以使用Suspend-Message命令,带上-identity参数指名要操作的队列中的邮件。
Suspend-Message -Identity ‘EX01\5272\19460496818233’
然后可以使用Resume-Message命令来恢复该邮件的传递:
Resume-Message -Identity ‘EX01\5272\19460496818233’
Remove-Message命令可以从队列里删除掉该邮件,但是注意有一个参数-WithNDR,即要不要返回发件人一条信息通知一下他,如果咱们这里不要返回NDR,那么该参数就置为$False:
Remove-Message -Identity ‘EX01\5272\19460496818233’-WithNDR $False
注意,在使用Remove-Message之前,不需要先暂停掉整个队列。
Exchange 2013还提供了另外的命令以供管理员操作邮件,即Export-Message与AssembleMessage。可以非常简单的选择邮件并且Export该邮件,包括该邮件的各个组成部分,导出为一个文本文档,Export邮件动作并不会将其从队列中移除。需要注意的是,要Export邮件,就必须得先暂停队列,或者是Suspend-Message。导出的邮件可以被检查或者编辑,然后重新放到分拣或者是重播目录里再次发送。这样就有一个后门可以……不,有一个便捷的方式可以先将某台队列卡住的服务器上队列里的邮件弄出来放到另一台可以到达目的地的服务器上进行发送。
Export-Message的用法还是指定邮件的-Identity参数,而且该命令导出的是一个二进制对象,还得配合上一个脚本AssembleMessage.ps1来编译为可以阅读的.eml格式文件,咱们可以用一系列简单的管道调用来完成这一系列操作:
Get-Message -Identity ‘EX01\5272\19460496818233’ | Suspend-Message | Export-Message | AssembleMessage –Path c:\exporttemp\
如果导出一个队列里的所有邮件就比较麻烦,因为AssembleMessage脚本一次只能调用一封邮件对象,所以咱们这里得用上一点Code的技巧:
$theMessages = @(Get-Message -Queue ‘EX01\5272’)
$theMessages | foreach {$i++; Export-Message $_.Identity | AssembleMessage -Path ("c:\temp"+$i+ ".eml")}
第一行的意思是在指定队列里取出所有的邮件,并且存储为一个数组,第二行语句则是遍历该数组,将数组中的每一个元素(每一封邮件)传递给Export-Message,接着由AssembleMessage处理并导出为文件。
暂停和恢复队列
前面已经提到过,一个队列可以有多种状态:暂停,活动,重试,就绪等等…在有些场景下,管理员当然也会希望针对队列按照自己的要求进行操作,比方临时性的暂停往某个特定的远程域投递邮件,或者是让Exchange立即开始重试投递上一次投递失败的邮件。
这时候就涉及到Resume-Queue、Suspend-Queue、Retry-Queue两条命令了。使用也非常简单,后面带上队列名就可以了,远程SMTP域名也可以,因为队列数据库可以通过这两者来识别你具体要进行操作的队列。
Suspend-Queue EX01\5272
Suspend-Queue Contoso.com
暂停队列的操作需要Confirm,而恢复或者是重试则不需要确认。而且这三条命令也支持使用-Filter参数来进行筛选批量操作,这样你就可以让服务器上所有处于“重试”状态的队列马上进行重试投递了:
Retry-Queue -Filter {Status -eq “retry”}
通过分拣目录提交邮件
分拣目录一般作用是提供给某些应用生成邮件存放在这,然后传输服务从这个目录读取邮件并进行投递。比如某些监控应用的组件探测到某台服务器的内存占用超标,于是它就会生成一封邮件类似下面的格式:
To: xuqi@contoso.com
From: servermonitor@contoso.com
Date: 14 July 2015 04:52AM
Subject: 【紧急】邮件前端Edge Transport内存使用率超过9%
MIME-Version: 1.0
Content-Type: text/html; charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head>
<body><pre>设备名称:邮件前端
设备地址:10.0.0.133
设备类型:windows
告警内容:内存超过9%
</pre></body></html>
默认情况下,分拣目录位于%ExchangeInstallPath% \TransportRoles\Pickup\,也可以使用Set-TransportServer命令来修改该路径:
Set-TransportServer –Identity MBX02 –PickupDirectoryPath ‘D:\Exchange\PickupDirectory’
基本思路就是,应用程序按照基本SMTP邮件格式创建一封.eml扩展名的文本邮件,然后放到Pickup目录中。每5秒间隔Exchange会检查一次这里(不能修改),然后传输在目录中找到的任何.eml文件。
其他不是以.eml结尾的文件会被忽略掉,Exchange每5秒钟会从分拣目录取走12封邮件进行处理,如果超过12封则剩下的会在下一次5秒进行处理。可以通过Set-TransportServer里的参数进行调整这个邮件量,比方我这里调整成每分钟处理250封,那么每5秒处理250/12=20.8333封邮件。:
Set-TransportServer –PickupDirectoryMaxMessagesPerMinute 250
处于分拣目录的.eml文件首先被重命名为.tmp扩展名的文件,然后Exchange会检测该文件是否存在必要的结构以转换成正常的邮件。如果存在同名的.tmp文件,则会重命名为<原始文件名><日期>.tmp的格式,如果再重命名失败,则就生成日志报错,然后处理下一个文件。如果没问题的话,系统将向.tmp文件发出一个delete on close指令,文件虽然显示仍然位于pickup目录,但是无法打开。转换好的邮件成功进入提交队列之后,系统发出close指令,.tmp命令就被移除。如果删除失败,将生成事件日志错误。如果分拣目录中存在 .tmp 文件时重新启动 Microsoft Exchange 传输服务,则所有的 .tmp 文件将重命名为 .eml 文件,并将被重新处理。这可能会导致邮件重复传输。
邮件文件的基本要求如下:
1、 邮件文件必须是符合基本 SMTP 邮件格式的文本文件。支持 MIME 邮件头字段和内容。
2、 邮件文件的文件扩展名必须是 .eml。
3、 在邮件头的 Sender 或 From 邮件头字段中必须至少存在一个电子邮件地址。如果在 Sender 和 From 字段中各存在一个电子邮件地址,则 From 字段中的电子邮件地址将在邮件信封中用作邮件的原始发件人。
4、 Sender 字段中只能存在一个电子邮件地址。不允许存在多个电子邮件地址。如果 From 字段中只存在一个电子邮件地址,则 Sender 字段为可选项。
5、 From 字段中允许存在多个电子邮件地址,但是 Sender 字段中还必须只存在一个电子邮件地址。Sender 字段中的地址随后将在邮件信封中用作邮件的原始发件人。
6、 To、Cc 或 Bcc 字段中必须至少存在一个电子邮件地址。
7、 邮件头和邮件正文之间必须存在一个空行。
8、 邮件头的最大大小为 64 KB,最大收件人数为 100。可以使用 Set-TransportService cmdlet 更改这些限制。这些设置只影响分拣目录。
Exchange将从邮件头中移除Received、Resent-*、Bcc栏的内容,如果只有Bcc栏里有收件人地址,Exchange会使用Undisclosed Recipients来代替To一栏的内容,即收件人不详。如果日期和Message-ID两个字段丢失,Exchange会对其进行修改,使用格式 <GUID>@<defaultdomain> 添加一个 Message-Id 字段与添加分拣目录进行邮件处理的日期和时间。
重播目录
重播目录用于重新提交导出的 Exchange 邮件以及从外部网关服务器接收邮件。类似分拣目录一样,Exchange每5秒钟检查一次重播目录,并且处理在里面发现的邮件信息。这些邮件已针对重播目录进行格式化。管理员不应该手动去增加重播目录中的内容,因为放在这里的邮件内容大量使用X-HEADER字段,非常容易弄错。所以如果要手动提交新邮件,还是使用分拣目录吧。
关于重播目录的更多,请参考:https://technet.microsoft.com/zh-CN/library/bb124230(v=exchg.150).aspx#ReplayReqs
到了这里终于是结束了队列这一章,如果有什么不明白的可以留言交流,下一章我们聊聊比较轻松的话题:邮件节流。