SMTP 服务存储驱动程序

 

上一次修改主题: 2005-06-21

高级排队引擎将 MailMsg 对象(内存中的邮件对象,可以实现快速处理)从一个接收器发送到另一个接收器。如果邮件驻留在 NTFS 上的 \Queue 目录中,MailMsg 对象将由邮件传输信封以及指向实际物理邮件的指针组成。如果邮件驻留在 Exchange 存储中,指针将指向邮件的 RFC 822 内容(在流式数据库中的临时文件中)。请注意,事件接收器不直接处理 MAPI 邮件,而且,当 MAPI 邮件在传输子系统中处理时,对邮件进行的任何更改都不具有持久性。分类程序等组件主要使用邮件指针来读取邮件内容中的数据。高级排队引擎在收到删除请求时也使用邮件指针来管理邮件的删除。

note注意:
MailMsg 属性流是传输组件用来对邮件进行永久更改的主要机制。MailMsg 属性流在两次服务重启之间具有持久性。

为了在内存中为收到的邮件创建 MailMsg 对象并处理实际的邮件,高级排队引擎使用下列存储驱动程序:

  • NTFS 存储驱动程序 该存储驱动程序在 NTFSDrv.dll 中实现,后者位于 \Windows\System32\Inetsrv 文件夹中。这是 Windows Server 2003 附带的基础存储驱动程序。它在文件系统中为 MailMsg 对象的内容以及邮件传输信封属性提供永久存储。
  • Exchange 存储驱动程序 该存储驱动程序在 Drviis.dll 中实现,后者位于 \Program Files\Exchsrvr\bin 文件夹中。Exchange Server 2003 实现此驱动程序,以便在 Exchange 存储中为 MailMsg 对象的内容以及传输信封属性提供永久存储。此存储驱动程序还处理本地邮件传递。
note注意:
写入到邮件内容中的更改并不总是具有持久性。如果邮件由 Exchange 存储驱动程序备份,更改将丢失,因为 Exchange 存储只能处理临时的邮件副本。

NTFS 存储驱动程序

SMTP 服务在确认传输并断开与远程主机的 SMTP 连接之前在硬盘驱动器上存储入站邮件。当邮件通过 SMTP 协议引擎到达时,数据以 NTFS 文件(.eml 文件)的形式写入到文件系统上的 \Queue 文件夹中。该文件夹位于 SMTP 虚拟服务器的 \Mailroot 目录中。默认 SMTP 虚拟服务器的 \Mailroot 目录的路径为:\Program Files\Exchsrvr\Mailroot\Vsi 1。如果您在 Exchange 系统管理器上创建额外的 SMTP 虚拟服务器,那么,根据该 SMTP 虚拟服务器的数字,额外的 \Vsi x 文件夹结构也将在 \Mailroot 目录中相应地创建出来。所有 \Vsi x 目录都位于 \Program Files\Exchsrvr\Mailroot 下,并顺序命名(即 \Vsi 1、\Vsi 2,依此类推)。

note注意:
Exchange Server 2003 安装程序将 SMTP 服务的 \Mailroot 目录从 \Inetpub\Mailroot 移入 \Program Files\Exchsrvr\Mailroot 中。前一个文件夹结构不会被删除。但是,以前的 \Pickup 和 \Queue 文件夹中的任何邮件都不会传递。要发送这些邮件,必须手动将其移入 SMTP 虚拟服务器的当前 \Pickup 文件夹中。

每个 \Vsx 文件夹都有三个或四个子文件夹,分别实现下面讲述的目的:

  • \Badmail 此文件夹用于保存无法送达的邮件。无法送达的邮件提示高级排队引擎将邮件随同 NDR 一起返还给发件人。如果无法传递 NDR,邮件将保存在 \Badmail 文件夹中的三个独立文件中。

  • \Pickup 此文件夹提供了另一种发送电子邮件的方法。可以将文本文件形式的邮件(格式采用 RFC 822)放入此文件夹中以等待传递。Inetinfo 进程使用 ATQ 中的一个线程来监视每个 SMTP 虚拟服务器的 \Pickup 目录。此线程立即获取 \Pickup 文件夹中的所有邮件,并在 \Queue 目录中创建一个新文件,然后分析 \Pickup 目录中的文件的内容,并将数据写入到 \Queue 目录中的文件中。请注意内容可能在此过程中被修改。例如,“x-sender”头和“x-receiver”头不复制到已写入到 \Queue 目录中的文件的内容中。
    下面是 Internet 文本邮件的一个示例,该邮件具有扩展的收件人和发件人头信息。“x-receiver”头标识一个收件人。如果要包含多个收件人,应当为每个收件人添加一个“x-receiver”头。头信息必须出现在文本文件的最前面,并且“x-sender”头应首先列出。按照 RFC 822,头信息与邮件正文之间必须有一个空行。
    邮件项目的文件名并不重要。SMTP 服务使用它自己的逻辑来命名 \Queue 目录中的邮件文件,并在末尾追加 .eml 文件扩展名,如 NTFS_7224ae2001c4125c0000001b.eml。
    x-sender: Ted@contoso.com
    x-receiver: Birgit@fabrikam.com
    From: Ted@contoso.com
    To: Birgit@fabrikam.com
    Subject: RFC 822 Pickup Message

    This message is passed to the SMTP service through the \Pickup directory.

    note注意:
    应在文件系统上的另一个文件夹中创建文本邮件,然后再将邮件移入 \Pickup 文件夹中。为了避免与所监视的 SMTP 服务冲突,不应直接在 \Pickup 文件夹中创建文件。
  • \Queue 此文件夹存放通过 SMTP 收到的、当前正等待通过 SMTP 传输到远程目标的所有邮件。但是,当邮件在 SMTP 传输子系统中处理时,通过 Exchange 存储收到的邮件不在该目录中。如果连接忙或者当前不可用,邮件可能堆积在该文件夹中。

    note注意:
    高级排队引擎按照指定的时间间隔尝试重新发送 \Queue 文件夹中的邮件。可以在 Exchange 系统管理器的 SMTP 虚拟服务器属性中的“传递”选项卡上配置这些时间间隔。但是,对 \Queue 文件夹的内容不进行定期扫描。只有服务启动或者 SMTP 虚拟服务器重新启动时才扫描 \Queue 文件夹的内容。
  • \Filter 默认情况下,此文件夹不显示。启用了特定虚拟服务器的邮件筛选功能之后,当筛选到第一封邮件时,该文件夹自动创建。要启用邮件筛选,请从 Exchange 系统管理器中,选择 SMTP 虚拟服务器属性,再选择“常规”选项卡,然后单击“高级”。

    note注意:
    此外,域控制器上还有一个 \Windows\NTDS\Drop 文件夹,SMTP 服务使用该文件夹将站点之间的目录复制邮件传递到 Active Directory 中。\Drop 文件夹不用于传递 Exchange 邮件。

重新定位 \Mailroot 目录

在 Exchange Server 2003 中,使用 Exchange 系统管理器 SMTP 虚拟服务器属性中的“邮件”选项卡,可以将 \Badmail 和 \Queue 文件夹移至文件系统中的另一个位置。\Badmail 和 \Queue 文件夹对于 Exchange 邮件处理功能而言是两个最重要的文件夹,因为它们是 SMTP 服务使用的主要文件夹。通过使用 ADSI Edit (AdsiEdit.msc) 对 Active Directory 中的 SMTP 虚拟服务器对象设置 msExchSmtpPickupDirectory,还可以移动 \Pickup 文件夹。元数据库更新服务将配置设置传输到 IIS 元数据库中,这一点已在本部分前面说明。

不要将 \Mailroot 目录放置在 FAT 分区上,因为 FAT 分区不支持对文件对象使用备用数据流,并且它们还有其他限制。例如,FAT16 分区最多支持 65,535 个文件。在任务繁忙的桥头服务器上,这会导致问题。如果队列中的邮件趋于饱和,有可能会占用条目以创建新文件。但是,由于每个邮件都需要三个文件,因此这是一个很复杂的过程。由于 FAT 分区不能使用备用数据流,因此 NTFS 存储驱动程序必须为每个邮件创建三个不同的文件,而不是创建一个文件及两个备用数据流。FAT 在大型卷上不能很好地工作,因为它的容错能力很小,并且在意外的系统中断后无法恢复。如果将 \Mailroot 目录放在高性能的磁盘子系统上,例如,放在独立磁盘冗余阵列 (RAID) 上,可能会对性能有所改善。具有八到十个磁盘的 RAID 0+1 对于大量邮件传递而言是一个好的开端。具有大于 64MB 缓存的 RAID 控制器也会对性能有所帮助。

note注意:
SMTP 协议引擎处理的每一封邮件都提交到磁盘中,然后读入 MailMsg 对象中。

Exchange 存储驱动程序

Exchange 存储驱动程序解决了 Exchange Server 2003 传输体系结构中一个有意思的问题。高级排队引擎的线程在 Inetinfo 进程中运行,但不是所有的邮件都通过 SMTP 协议引擎接收。正如下图所示和邮件路由体系结构中所讨论的那样,来自 MAPI 客户端(例如 Outlook)以及来自 Exchange MTA 的邮件将通过 Microsoft Exchange Information Store 服务被传递到 SMTP 传输子系统。由于它们不通过 SMTP 协议引擎接收,因此必须以另一种途径将这些邮件传递到高级排队引擎。Exchange 存储驱动程序提供了这种替代的机制。

此外,邮件可能不通过 SMTP 协议引擎离开运行 Exchange Server 2003 的服务器。邮件可能发送到在本地 Exchange 存储中拥有邮箱的收件人,在这种情况下,邮件将通过 Exchange 存储驱动程序传递。通过 Exchange MTA 到达远程收件人的邮件也必须传输到 Exchange 存储,因为 Exchange MTA 在 Exchange 存储中有它自己的出站邮件队列。Exchange MTA 控制到本地路由组中的 Exchange 5.5 服务器的邮件传输,控制到远程 Exchange MTA 以及使用 X.400 连接器的非 Exchange X.400 MTA 的邮件传输,还控制到使用基于 MAPI 的邮件连接器的非 Exchange 邮件系统的邮件传输。有关 Exchange MTA 的详细信息,请参阅 X.400 传输体系结构

d8443168-200e-44ae-adc5-32f04336df22

Exchange 存储驱动程序体系结构

如下图所示,Exchange 存储 (Store.exe) 和 IIS Inetinfo 进程 (Inetinfo.exe) 在操作系统中是两个独立的进程。了解这一点很重要。独立的进程彼此之间不直接共享各自的虚拟地址空间,因此 Inetinfo.exe 不能访问 Store.exe 虚拟地址空间中的数据,反之亦然。要将 MAPI 邮件放入高级排队引擎的提交前队列中,Exchange 存储驱动程序必须将函数调用从 Store.exe 的虚拟地址空间传递到 Inetinfo 进程的虚拟地址空间。要将邮件传递到本地的收件人邮箱中或者传递到 Exchange MTA 邮件队列中,Exchange 存储驱动程序还必须将另一方向上的函数调用从 IIS Inetinfo 进程传递到 Exchange 存储。

f6cf1eac-fc0a-448c-83e9-67ca9b4c7727

Exchange 存储驱动程序事件接收器使用下面的三个关键组件来启用 Exchange 存储与 Inetinfo 之间的进程间通信。这些组件共同组成了 Exchange 存储驱动程序。

  • Drviis.dll 此 DLL 在 Inetinfo 进程中运行,并通过 SMTP StoreDriver COM 事件与高级排队引擎通信。

  • Epoxy.dll 此 DLL 实现了 IIS 与 Exchange 存储之间的 Exchange 进程间通信层 (ExIPC)。使用此通信层,IIS 和 Exchange 存储可以跨越进程边界快速直接地交换数据。这是通过共享内存来实现的,而共享内存是通过此 DLL 加载到两个进程的虚拟地址空间中的。
    Epoxy.dll 的共享内存模型基于 Shared Memory Circular Queue (SMQ) 模型。这意味着在 Epoxy.dll 层内部,在每个方向上都使用固定大小的独立循环队列来传输数据。Epoxy.dll 层包含绑定工具,存储驱动程序可以使用此工具在 IIS 与 Exchange 存储之间创建并连接任意数目的循环队列。此绑定工具包含一个中央队列管理器,此管理器监视通过此进程进行通信的队列。此绑定工具还用于取消队列绑定以及清理队列。

    note注意:
    Epoxy.dll 使用本地远程过程调用 (LRPC) 和共享内存堆在 IIS 与 Exchange 存储之间传递数据。共享内存仅适用于运行在同一计算机上的进程。远程进程之间的通信(例如,在完全的远程过程调用 (RPC) 情形中的通信)不可能使用 Epoxy.dll 来实现。
  • ExSMTP.dll 此 DLL 在 Exchange 存储进程中运行,它使协议存根可以通过 EPOXY 以及 Dviis.dll 的 Inetinfo 接口与 Exchange 存储通信。

Exchange 可安装文件系统

为了尽量缩小 Exchange 存储驱动程序与 Windows Server 2003 附带的 NTFS 存储驱动程序之间的区别,Exchange Server 2003 在 Exchange 存储中通过流式数据库 (.stm) 实现了一个 Microsoft Win32 文件系统。Exchange 存储的 .stm 文件以固有格式(纯文本、MIME 或 UUEncode)保存 Internet 邮件,而对应的 .edb 文件则以 MAPI 格式存储邮件。流式数据库的 .stm 文件中没有目录结构。Exchange 存储的结构在 .edb 文件的邮件表中维护。在 Exchange Information Store 服务体系结构中,可以阅读有关邮件数据库的体系结构和设计的详细信息。

Exchange 可安装文件系统由下列主要组件组成(如下图所示):

  • Exifs.sys 这是内核模式驱动程序,Exchange 存储驱动程序可用它来从邮件数据库中读取项目,以及将项目写入到邮件数据库中。此驱动程序为 Exchange 存储提供 Win32 文件 API。
  • Exwin32.dll 这是在 Store.exe 进程中运行的 Exchange 存储扩展,它处理来自 Exifs.sys 的文件级操作请求(如创建、打开、重命名、提交、删除等等)。请注意这是用于 Win32 文件系统操作的用户模式组件。SMTP 传输子系统不使用 Win32 文件。
  • Ifsproxy.dll 这是 Exwin32.dll 周围的用户模式包装,它为 Win32 文件系统调用提供简单的接口。Ifsproxy.dll 还在 .stm 文件的可用空间分配中扮演了至关重要的角色。当在数据库中分配可用空间时,ExIFS 向 ESE 请求空间。例如,如果 Exchange 存储驱动程序在 Exchange 存储中新建一个项目以便在本地传递邮件,ExIFS 将向 ESE 请求空间。

ExIFS 通过两种不同模式来支持文件访问。

  • Win32 此模式基于文件名,使用此模式,可以通过与磁盘驱动器类似的文件系统使 Exchange 存储可见。操作系统将文件命名空间 \\.\backofficestorage 与 Exchange 可安装文件系统对应。通过此命名空间可访问所有私人数据库和公用数据库。格式为 file://./backofficestorage/域名,如 file://./backofficestorage/fabrikam.com。

    note注意:
    Win32 文件主要由 HTTP-DAV 协议以及 EXOLEDB 和 CDOEX API 使用。
  • EA EA 是扩展特性 (extended attribute) 的首字母缩写。扩展特性存储在每个邮件的一个特殊属性中。ExIFS 将扩展特性复制到名为散点列表 (SLIST) 的内存结构中。散点列表基本可称得上是用于打开邮件项目的二进制大对象 (BLOB)。EA 文件供 Exchange 传输子系统在内部使用,用户通过任何一种可用的 API 或协议都看不到此类文件。EA 路径可能如下所示:\;E:\Ted\$705260a-46c4-454d-b0dd-96b9c605364\369b6c05-0256-46c7-fad3-54ffa867d089-0000001e。

    note注意:
    SMTP 传输子系统中的组件仅使用扩展特性在 ExIFS 中打开文件。

c731bd3a-65a3-498a-adb6-1023ef405f69

出站邮件传输

Exchange 存储驱动程序对出站邮件执行以下步骤,从而将邮件传递到高级排队引擎的提交前队列。

  1. 当 Outlook 用户发送邮件时,邮件被放入用户邮箱的发件箱中,并进行相应的传递标记。

  2. Exchange 存储将邮件放入其内部的 SendQ 文件夹中,并调用 Exchange 存储驱动程序以便将邮件传输到 IIS。

  3. ExSMTP.dll 确定邮件的文件夹标识符 (FID) 和邮件标识符 (MID),并读取与传输有关的邮件属性(如发件人地址和收件人地址,以及是否要求提供传递报告)。ExSMTP.dll 重新设置这些属性的格式,使其成为 MailMsg 对象的属性流。ExSMTP.dll 包含邮件的 FID 和 MID,这样 Drviis.dll 之后便能够根据需要在 Inetinfo 一侧获取邮件内容。FID 唯一地标识 Exchange 存储中包含该邮件的邮件文件夹。MID 唯一地标识邮件。

    note注意:
    邮件信封不包含邮件内容。Epoxy.dll 用于将邮件信封信息传递到 Inetinfo。ExIFS.sys 用于在必要时封送邮件内容。如果邮件是从本地传递到本地,或是从本地传递到 Exchange MTA,则可能永远也不需要访问邮件内容。只有在将邮件传递到其他邮箱存储中的收件人,或者对邮件进行出站 SMTP 传递,或者接收器在传输事件过程中请求了 RFC 822 内容时,才需要生成 RFC 822 内容。
  4. ExSMTP.dll 通过循环共享内存队列将指向共享内存部分的指针传递给 Drviis.dll。如下图所示,指针指向所分配的共享内存中包含信封属性流、文件夹 ID 和邮件 ID的部分。
    4f97f61e-5ace-4e9f-93ea-1a18691f5f22

    note注意:
    操作系统除了在运行过程中为代码和堆栈分配内存外,还使用堆来动态地分配和释放内存。
  5. Drviis.dll 在 Inetinfo 的一侧使指针出列(也就是将指针从循环内存队列中删除)。该指针指向存放信封属性流、文件夹 ID 和邮件 ID 的共享内存。

  6. Drviis.dll 使用该内存指针将共享内存中的属性流读入 MailMsg 对象中。本部分前面已提到,MailMsg 对象由邮件传输信封(提供将邮件路由到下一跃点所必需的信息)以及指向实际物理邮件的指针组成。此时,MailMsg 对象具有邮件传输信封信息,因为 MailMsg 对象的全部属性都位于由 ExSMTP.dll 准备的共享内存块中。

  7. Drviis.dll 将 MailMsg 对象放入提交前队列中。传输子系统现在可以处理该邮件。

  8. 高级排队引擎触发其传输事件和系统事件,以便调用基础分类程序和 Exchange 分类程序、路由引擎以及已注册的其他事件接收器,从而对邮件进行处理。大多数传输处理都是使用邮件传输信封来执行的。除非明确要求,否则不打开邮件内容。例如,Exchange 分类程序可能必须执行内容转换。如果必须通过 SMTP 将邮件传输到下一跃点,那么 SMTP 协议引擎必须访问 RFC 822 格式的邮件内容。

    note注意:
    在本地传递 MAPI 邮件时(在同一台服务器上发送和接收邮件,而不需要进行内容转换),SMTP 传输组件从不打开内容(如果未安装试图读取 RFC 822 邮件内容的任何自定义事件接收器,如存档接收器)。
  9. 当传输子系统中的组件通过调用 MailMsg 对象的 ReadContent 或 WriteContent 方法来打开邮件内容时,会将邮件内容作为文件来访问,就好像访问文件系统上的 \Queue 文件夹中的邮件项目(例如,必须通过 SMTP 发送的邮件)一样。当邮件通过 Exchange 存储提交时,将使用 ExIFS 文件,而不是 NTFS 文件。

  10. 对于 Exchange 存储中的邮件,MailMsg 调用 Drviis.dll 以打开普通的文件句柄。通过 RFC 822 格式请求邮件内容。对于已分类的邮件,属性流还可能包含其他的一些出站转换值,这些值可用于在检索内容时要求特定的格式。

  11. 本部分前面已提到,Drviis.dll 将指向物理邮件的指针保存在 MailMsg 对象中。该指针由邮件的文件夹 ID 和邮件 ID 组成。Drviis.dll 使用该指针以及其他任何内容格式参数将邮件请求数据包通过 Epoxy.dll 传递到 Store.exe 进程内部的 Exsmtp.dll。

  12. Exsmtp.dll 使用文件夹 ID 和邮件 ID 来调用内部的 Exchange 存储方法 EcGetMime,以请求 RFC 822 格式的邮件内容,同时还指定 Drviis.dll 可能已传递的其他任何参数。

    note注意:
    在应用程序事件日志条目中,您可能会注意到 EcGetMime 调用的事件来源为 MSExchangeTransport,事件类别为 Exchange 存储驱动程序。有关详细信息,请参阅 Microsoft 知识库文章 319682“XGEN: The Exchange 2000 Information Store Reports an Event ID327 Warning Message and Virtual Memory May Be FragmentedXGEN:The Exchange 2000 Information Store Reports an Event ID327 Warning Message and Virtual Memory May Be Fragmented”(英文)。
  13. 由于邮件是通过 Outlook 提交的,因此不是 RFC 822 格式。邮件是 MAPI 格式,存储在 .edb 文件中。因此,当使用传输组件或 Internet 客户端来打开邮件时,Exsmtp.dll 所请求的内容不存在于 ExIFS 使用的流式数据库中。

    note注意:
    Exchange Server 2003 将从 MAPI 客户端、X.400 连接器或基于 Exchange 开发工具包 (EDK) 的连接器收到的邮件以 MAPI 格式存储在 .edb 数据库中。
  14. 如果邮件不存在于流式数据库中,则必须使用 .edb 数据库中用于描述邮件的各个属性及各种表来创建邮件。因此,Exchange 存储使用 IMAIL 创建临时的 ExIFS 文件,并根据所传递的请求格式参数相应地将邮件从数据库中提交到该 RFC 822 格式的文件中。

    note注意:
    Exchange 分类程序使用 IMAIL 机制对内容应用邮件格式,这些格式是在 Exchange 系统管理器中对 Internet 域所指定的,或者是由用户在 Outlook 中针对每个收件人所指定的。如果没有向 IMAIL 传递任何格式参数,IMAIL 便会将 MAPI 邮件设置为 Summary TNEF (S/TNEF) 格式。
  15. 在 Exchange Server 2003 中,ExIFS.sys 创建临时的 ExIFS 文件,这样,即使试图修改 RFC 822 内容的事件接收器出现故障时,流式数据库中已提交的页也不会遭到破坏。事件接收器不在实际的内容页上执行写入操作,而仅仅在副本上执行写入操作。

  16. 一旦生成了临时的 ExIFS 文件,文件句柄便会重新传递给 Exsmtp.dll。Exsmtp.dll 调用 ExIFS,以检索指向该文件在流式数据库中占用的页(也就是 ExIFS 复制到名为散点列表的内存结构中的扩展特性)的指针。

  17. Exsmtp.dll 将散点列表复制到共享内存中,并将列表通过 Epoxy.dll 重新传递给 Drviis.dll。

  18. Drviis.dll 使用该散点列表来打开扩展特性 (EA) 文件形式的 ExIFS 文件。现在 Drviis.dll 具有开放的 ExIFS 文件句柄,它将该文件句柄返回给 MailMsg,这样后者便能够处理对 RFC 822 邮件内容的 ReadContent 请求或 WriteContent 请求。

  19. SMTP 协议引擎现在能够读取邮件内容,并能够将数据通过 SMTP 传输到远程主机或 Exchange 服务器。

  20. 成功传输邮件后,高级排队引擎删除已不再有用的 MailMsg 对象。相应地,高级排队引擎调用 Exchange 存储驱动程序 (drviis.dll) 来删除邮件。Drviis.dll 创建一个将邮件从共享内存中删除的请求,并将该请求通过 EPOXY 传输给 Exsmtp.dll。然后,Exsmtp.dll 将邮件从发件人的发件箱中移入“已发送邮件”文件夹中,或者删除该邮件。

note注意:
每次请求内容时都会重新生成内容。每次请求内容时,都通过一个临时的 ExIFS 文件来返回该内容。只要该文件保持打开,就可以一直使用它。文件关闭后,将自动被丢弃,因为它仅仅是邮件的一个临时副本。为了尽量减少生成周期,高级排队引擎使内容文件一直保持打开状态,直到邮件已传输或已送达。只有在邮件已准备删除或者已计划在稍后的时间重试时才关闭内容文件。如果远程服务器不可用,或者队列中当前有 10,000 个以上的内容文件打开并且正在处理,可能会稍后重试邮件。如果当前有 10,000 个以上的内容文件打开并且正在处理,必须关闭某些文件,以便为其他邮件腾出空间。当稍后再次打开邮件时(例如,由于重试邮件传输而再次打开邮件时),必须重新生成内容。IMAIL 在文件打开时生成新的临时 ExIFS 文件。了解这一点很重要。文件关闭时对该 ExIFS 文件的所有更改都将丢失。

入站邮件传输

Exchange 存储驱动程序对必须传递到本地收件人或 Exchange MTA 的入站邮件执行下列步骤。

  1. 邮件通过 SMTP 协议引擎或 Exchange 存储驱动程序放入提交前队列中,然后进行分类并进行相应的传递标记。

  2. 高级排队引擎触发 SMTP StoreDriver 事件,通知 Exchange 存储驱动程序接收器必须将邮件传输到 Exchange 存储。

  3. 如果邮件是通过 SMTP 连接或 \Pickup 文件夹接收的,将仍然位于 \Queue 文件夹中。Drviis.dll 相应地调用 CreateFile() 以便在 ExIFS 中创建一个新文件,然后将邮件项目复制到这个位于 Exchange 存储的新建文件中。

    note注意:
    如果在同一个邮箱存储中发送和接收邮件,邮件内容将不会复制到该存储中。如果在同一服务器上的不同邮箱存储中发送和接收邮件,将使用 RFC 822 S/TNEF 作为中间格式复制邮件。内容不会从 Exchange 存储封送到 Inetinfo 进程。此处理是在 Exchange 存储中完成的。IMAIL 根据 Exsmtp.dll 的请求将 S/TNEF 格式的内容提交到 ExIFS 文件中。Exchange 存储使用该 ExIFS 文件构建新邮件,以便将邮件传递到包含收件人邮箱的邮箱存储中。
  4. 如果邮件是通过 SMTP/Pickup 接收的,ExIFS 将返回散点列表,以指示新项目的数据在流式数据库中的位置。

  5. Drviis.dll 分配共享内存堆中的内存,并将散点列表放入所分配的内存块中。然后,指向所分配的那部分共享内存的指针将被放入 Store.exe 进程一侧的队列中。

  6. ExSMTP.dll 从 Exchange 存储一方的队列中获取该指针。该指针指向存放入站邮件的散点列表的共享内存。

  7. ExSMTP.dll 使用散点列表调用 Ifsproxy.dll,以接收从 ExIFS 返回的文件句柄。要将项目提交到数据库中,必须创建邮件,因此 ExSMTP.dll 通过邮件数据库外部接口 (MDBEIF) 来调用 Exchange 存储内核 (Store.exe),以创建邮件对象。然后,ExSMTP.dll 明确地将内容的文件句柄传递到 Exchange 存储内核,Exchange 存储内核再将文件句柄传递到 ESE,这样便能够在 ExSMTP.dll 提交邮件对象时提交数据。

    note注意:
    页校验和存储在基于 MAPI 的数据库文件 (.edb) 中。流式数据库文件 (.stm) 不包含页校验和。
  8. 当有新邮件到达时 Exchange 存储通知 Outlook,然后 Outlook 在收件箱中列出该邮件。

  9. ExSMTP.dll 通过 EPOXY 通知 Drviis.dll 传递已完成,然后 Drviis.dll 将肯定的结果返回给高级排队引擎。然后高级排队引擎可以相应地删除该邮件,具体过程如下所述:

    • 邮件是通过 SMTP 或 \Pickup 目录收到的 在 \Queue 目录中存在一个与邮件对应的 .eml 文件。高级排队引擎重新调用 MailMsg 以删除该邮件。由于 MailMsg 对象绑定到 NTFS 存储驱动程序,因此该调用被传递到 NTFSDrv.dll,然后由 NTFSDrv.dll 将邮件从文件系统上的 \Queue 目录中删除。
    • 邮件是通过 Exchange 存储驱动程序提交的 高级排队引擎重新调用 MailMsg 以删除该邮件。由于 MailMsg 对象绑定到 Exchange 存储驱动程序,因此该调用被传递到 Drviis.dll,Drviis.dll 将对 ExSMTP.dll 的 EPOXY 请求排队。然后,ExSMTP.dll 将邮件从发件人的发件箱中移入“已发送邮件”文件夹中,或者删除该邮件。
note注意:
如果发送给远程收件人的邮件是通过 \Pickup 目录或 SMTP 协议引擎到达的,那么这些邮件不会被放入 Exchange 存储中。它们保留在文件系统上的 \Queue 文件夹中,直到被成功传输到通向目标的路由路径中的下一个跃点。但是,分类程序可能对不通过 Exchange 存储驱动程序传递的邮件使用 Exchange 存储。因为分类程序可能需要生成传递状态通知,而此类通知在 Exchange 存储中创建。

传输重试

请注意,在分类和路由过程以及实际的传输过程中,通过 Exchange 存储驱动程序进入高级排队引擎的邮件保留在 Exchange 存储中。此类邮件不会被复制到 SMTP 虚拟服务器的 \Queue 文件夹中。如果由于连接失败而必须重试,这些类型的邮件也保留在 Exchange 存储中。无法立即传输的邮件会被移入到一个临时表中。因此,邮件从发件人的发件箱文件夹中消失,而复制到“已发送邮件”文件夹中(如果 Outlook 配置为在“已发送邮件”文件夹中保留所有邮件的副本)。邮件将一直保留在临时表中,直到被成功传输或者过期。使用 Exchange 系统管理器中的队列查看器管理单元,可以在“重试已失败邮件”队列中查看这些邮件。