SMTP Service Store Drivers

 

The advanced queuing engine passes a MailMsg object (an in-memory message object that allows for fast processing) from sink to sink. The MailMsg object is made up of a message transfer envelope and a pointer to the actual physical message, if the message resides in the \Queue directory on NTFS. If the message resides in the Exchange store, the pointer refers to the RFC 822 content of the message, which is in a temporary file in the streaming database. Note that event sinks do not work with MAPI messages directly, and any changes to a MAPI message during message processing in the transport subsystem are not persisted. Components, such as the categorizer, use the message pointer primarily to read data from the message content. The advanced queuing engine also uses the message pointer to manage the deletion of messages when requested.

Note

The MailMsg property stream is the primary mechanism that transport components use to make permanent changes to a message. The MailMsg property stream is persisted across service restarts.

To create the MailMsg object in memory for a received message and to work with the actual message, the advanced queuing engine uses the following store drivers:

  • NTFS Store Driver   This store driver is implemented in NTFSDrv.dll, which resides in the \Windows\System32\Inetsrv folder. This is the base store driver that comes with Windows Server 2003. It provides persistent storage for a MailMsg object's content and message transfer envelope properties on the file system.

  • Exchange Store Driver   This store driver is implemented in Drviis.dll, which resides in the \Program Files\Exchsrvr\bin folder. Exchange Server 2003 implements this driver to provide persistent storage for a MailMsg object's content and transfer envelope properties in the Exchange store. The store driver also handles local message delivery.

Note

Changes written to the content of the message are not always permanent. In the case of messages backed up by the Exchange store driver, changes are lost because the Exchange store works only with a temporary message copy.

NTFS Store Driver

The SMTP service stores inbound messages on a hard disk drive before it acknowledges the transfer and disconnects the SMTP connection to the remote host. When messages arrive through the SMTP protocol engine, the data is written to a \Queue folder on the file system in the form of an NTFS file (an .eml file). This folder resides in the \Mailroot directory of the SMTP virtual server. The path to the \Mailroot directory of the default SMTP virtual server is: \Program Files\Exchsrvr\Mailroot\Vsi 1. When you create additional SMTP virtual servers in Exchange System Manager, additional \Vsi x folder structures are created in the \Mailroot directory, according to the numeral of the SMTP virtual server. All \Vsi x directories are located under \Program Files\Exchsrvr\Mailroot and are named sequentially (that is, \Vsi 1, \Vsi 2, and so forth).

Note

The Exchange Server 2003 Setup program moves the \Mailroot directory of the SMTP service from \Inetpub\Mailroot to \Program Files\Exchsrvr\Mailroot. The previous folder structure is not deleted. However, any messages in the former \Pickup and \Queue folders are not delivered. To send these messages, you must manually move them to the current \Pickup folder of the SMTP virtual server.

Each \Vsx folder has three or four subfolders for the following purposes:

  • \Badmail   This folder is used to save undeliverable messages. An undeliverable message prompts the advanced queuing engine to return the message to the sender together with an NDR. If the NDR cannot be delivered, the message is saved in three separate files in the \Badmail folder.

  • \Pickup   This folder provides an alternative method to send e-mail messages. You can place messages in the form of text files, formatted according to RFC 822, in this folder for delivery. The Inetinfo process uses a thread from ATQ to monitor the \Pickup directory of each SMTP virtual server. This thread obtains any messages from the \Pickup folder immediately, creates a new file in the \Queue directory, and then parses the content from the file in the \Pickup directory and writes the data to the file in the \Queue directory. Note that the content might be modified during this process. For example, "x-sender" and "x-receiver" headers are not copied to the content written to the file in the \Queue directory.

    The following is an example of an Internet text message with extended header information for recipients and sender. The "x-receiver" header identifies a single recipient. If you want to include multiple recipients, add an "x-receiver" header for each recipient. The header must appear first in the text file, with the "x-sender" header listed first. According to RFC 822, there must be an empty line between the header information and the body of the message.

    The file name of the message item is not important. The SMTP service uses its own logic to name the message file in the \Queue directory and append an .eml file name extension, for example 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

    You should create the text messages in another folder on the file system and then move the messages to the \Pickup folder. To avoid conflicts with the monitoring SMTP service, do not create the files directly in the \Pickup folder.

  • \Queue   This folder holds all messages received through SMTP that are currently waiting for transfer to a remote destination through SMTP. However, messages received through the Exchange store are not in this directory during processing in the SMTP transport subsystem. Messages might accumulate in this folder if a connection is busy or currently unavailable.

    Note

    The advanced queuing engine attempts to resend messages in the \Queue folder at designated intervals. You can configure these intervals in Exchange System Manager, in the SMTP virtual server properties, on the Deliver tab. However, the content of the \Queue folder is not scanned at intervals. The content of the \Queue folder is scanned only when you start a service or when you restart an SMTP virtual server.

  • \Filter   By default, this folder is not present. It is created automatically when the first message is filtered, after you enable message filtering for a particular virtual server. To enable message filtering, from Exchange System Manager, select the SMTP virtual server properties, select the General tab, and then click Advanced.

    Note

    In addition, there is a \Windows\NTDS\Drop folder that the SMTP service uses on domain controllers to deliver inter-site directory replication messages to Active Directory. The \Drop folder is not used to deliver Exchange messages.

Relocating the \Mailroot Directory

In Exchange Server 2003, Exchange System Manager enables you to move the \Badmail and the \Queue folders to another location in the file system (in the properties of the SMTP virtual server, from the Messages tab). The \Badmail and the \Queue folders are the most important folders for Exchange message handling, because they are the main folders that the SMTP service uses. You can also move the \Pickup folder by setting the msExchSmtpPickupDirectory for the SMTP virtual server object in Active Directory using ADSI Edit (AdsiEdit.msc). The metabase update service transfers the configuration settings to the IIS metabase, as explained earlier in this section.

Do not place the \Mailroot directory on a FAT partition, because FAT partitions do not support alternate data streams to a file object, and they have other restrictions. For example, FAT16 partitions support a maximum of 65,535 files. This can be a problem on a busy bridgehead server. If a queue begins to fill, it is possible to deplete entries to create new files. However, this process is complicated by the fact that each message requires three files. Because alternate data streams are unavailable on a FAT partition, the NTFS store driver must create three different files for each message, instead of one file with two alternate data streams. FAT does not perform well on large volumes, because it provides minimal fault tolerance and no recoverability after an unexpected system halt. A positive performance impact may occur if you place the \Mailroot directory on a high-performance disk subsystem, such as a redundant array of independent disks (RAID). A RAID 0+1 with eight to ten disks is a good start for high-volume message delivery. A RAID controller with a cache larger than 64 megabytes (MB) also helps performance.

Note

Every message that is processed by the SMTP protocol engine is committed to disk and then read to a MailMsg object.

Exchange Store Driver

The Exchange store driver solves an interesting problem in the Exchange Server 2003 transport architecture. The threads of the advanced queuing engine run in the Inetinfo process, but not all messages are received through the SMTP protocol engine. As illustrated in the following figure and discussed in Message Routing Architecture, messages from MAPI clients, such as Outlook, and from the Exchange MTA, are passed to the SMTP transport subsystem through the Microsoft Exchange Information Store service. Because they are not received through the SMTP protocol engine, these messages must be passed to the advanced queuing engine in a different way. The Exchange store driver provides this alternative mechanism.

In addition, messages might not leave a server running Exchange Server 2003 through the SMTP protocol engine. A message might be addressed to a recipient with a mailbox in the local Exchange store, in which case the message is delivered through the Exchange store driver. Messages for remote recipients that are reached through the Exchange MTA must also be transferred to the Exchange store, because the Exchange MTA has its outbound message queue in the Exchange store. The Exchange MTA controls message transfer to servers running Exchange 5.5 in the local routing group, to remote Exchange MTAs and non-Exchange X.400 MTAs using an X.400 connector, or to a non-Exchange messaging system using a MAPI-based messaging connector. For more information about the Exchange MTA, see X.400 Transport Architecture.

Non-SMTP message transfer through the advanced queuing engine

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

Exchange Store Driver Architecture

It is important to understand that the Exchange store (Store.exe) and IIS Inetinfo process (Inetinfo.exe) are separate processes in the operating system, as indicated in the following figure. Separate processes do not share their virtual address spaces directly with each other, thus data in the virtual address space of Store.exe is not accessible by Inetinfo.exe and vice versa. To place a MAPI message in the pre-submission queue of the advanced queuing engine, the Exchange store driver must pass a function call from the virtual address space of Store.exe to the virtual address space of the Inetinfo process. The Exchange store driver must also pass a function call in the other direction, from the IIS Inetinfo process to the Exchange store, for local delivery to a recipient mailbox or to the Exchange MTA message queue.

Architecture of the Exchange store driver

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

The Exchange Store Driver event sink uses the following three key components to enable inter-process communication between the Exchange store and Inetinfo. Together these components form the Exchange store driver.

  • Drviis.dll   This DLL runs in the Inetinfo process and communicates with the advanced queuing engine through SMTP StoreDriver COM events.

  • Epoxy.dll   This DLL implements the Exchange inter-process communications layer (ExIPC) between IIS and the Exchange store. IIS and the Exchange store use this communication layer to rapidly exchange data directly across process boundaries. This is accomplished through shared memory that is loaded by means of this DLL to the virtual address space of both processes.

    The shared-memory model of Epoxy.dll is based on the Shared Memory Circular Queue (SMQ) model. This means that within the Epoxy.dll layer, individual circular queues of a fixed size are used for data transfer in either direction. The Epoxy.dll layer includes a binding facility that enables the store driver to create and connect an arbitrary number of circular queues between IIS and the Exchange store. This binding facility includes a central queue manager that monitors the queues that communicate through this process. This binding facility is also used for queue unbinding and cleanup.

    Note

    Epoxy.dll uses local remote procedure calls (LRPCs) and a shared-memory heap to pass data between IIS and the Exchange store. Shared memory works only for processes running on the same computer. Communication between remote processes, as in a full remote procedure call (RPC) scenario, is not possible using Epoxy.dll.

  • ExSMTP.dll   This DLL runs in the Exchange store process and implements the protocol stub to communicate with the Exchange store through EPOXY and the Inetinfo interface of Dviis.dll.

Exchange Installable File System

To minimize the differences between the Exchange store driver and the NTFS store driver that ships with Windows Server 2003, Exchange Server 2003 implements a Microsoft Win32 file system over the streaming databases (.stm) in the Exchange store. The .stm file of an Exchange store holds Internet messages in their native format (plain text, MIME, or UUEncode), while the corresponding .edb file stores messages in MAPI format. A streaming database has no directory structure in the .stm file. The structures of the Exchange store are maintained in message tables in the .edb file. You can read more about the architecture and design of the messaging databases in Exchange Information Store Service Architecture.

The Exchange installable file system is made up of the following main components (shown in the following figure):

  • Exifs.sys   This is a kernel-mode driver that the Exchange store driver can use to read and write items from and to messaging databases. This driver provides the Win32 file API for the Exchange store.

  • Exwin32.dll   This is an Exchange store extension that runs in the Store.exe process and handles requests for file-level operations (such as create, open, rename, commit, delete, and more) from Exifs.sys. Note that this is a user-mode component used for Win32 file system operations. The SMTP transport subsystem does not use the Win32 files.

  • Ifsproxy.dll   This is a user-mode wrapper around Exwin32.dll to provide a straightforward interface for Win32 file system calls. Ifsproxy.dll also plays a crucial role in free-space allocation in the .stm file. ExIFS requests space from ESE when allocating free space in a database. For example, if the Exchange store driver creates a new item in the Exchange store to deliver a message locally, ExIFS requests space from ESE.

ExIFS supports access to files in two different modes.

  • Win32   This mode is based on file names and is used to make the Exchange store visible through the file system similar to a disk drive. The operating system maps the file namespace \\.\backofficestorage to the Exchange installable file system. This namespace provides access to all private and public databases. The format is file://./backofficestorage/DomainName, such as file://./backofficestorage/fabrikam.com.

    Note

    Win32 files are used primarily by the HTTP-DAV protocol and EXOLEDB and CDOEX APIs.

  • EA   EA is the acronym for extended attributes, which are stored in a special property of each message. ExIFS copies the extended attributes to an in-memory structure called the scatter list (SLIST). The scatter list is basically a binary large object (BLOB) that can be used to open a message item. EA files are for internal use by the Exchange transport subsystem and are not visible to users through any one of the documented APIs or protocols. An EA path might look like this: \;E:\Ted\$705260a-46c4-454d-b0dd-96b9c605364\369b6c05-0256-46c7-fad3-54ffa867d089-0000001e.

    Note

    The components in the SMTP transport subsystem exclusively use extended attributes to open files in ExIFS.

Integration of IIS and the Exchange store

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

Outbound Message Transfer

The Exchange store driver performs the following steps for an outbound message to pass it to the pre-submission queue of the advanced queuing engine.

  1. When an Outlook user sends a message, the message is placed in the Outbox of the user's mailbox and marked for delivery.

  2. The Exchange store places the message to its internal SendQ folder and calls the Exchange store driver to transfer the message to IIS.

  3. ExSMTP.dll determines the folder identifier (FID) and message identifier (MID) of the message and reads transport-relevant message properties (such as sender and recipient addresses, and whether delivery reports are requested). ExSMTP.dll reformats these properties into a property stream for MailMsg object. ExSMTP.dll includes the FID and MID of the message, so that Drviis.dll can later fetch the message content on the side of Inetinfo if necessary. The FID uniquely identifies the message folder in the Exchange store that contains the message. The MID uniquely identifies the message.

    Note

    The message envelope does not contain the message content. Epoxy.dll is used to pass message envelope information to Inetinfo. ExIFS.sys is used to marshal the message content, if necessary. It might never be necessary to access the content of a message if it is a "local to local" or "local to Exchange MTA" delivery. The RFC 822 content only needs to be produced for delivery to recipients in other mailbox stores, for outbound SMTP delivery, or for sinks that request the content during a transport event.

  4. ExSMTP.dll passes a pointer to the shared memory section through a circular shared-memory queue to Drviis.dll. As indicated in the following figure, the pointer refers that portion of allocated shared memory that contains the envelope property stream, folder ID, and message ID.

    Inter-process communication using EPOXY

    4f97f61e-5ace-4e9f-93ea-1a18691f5f22

    Note

    A heap is used for allocating and freeing memory dynamically in addition to what the operating system allocates for the code and stack during run time.

  5. Drviis.dll de-queues the pointer on the Inetinfo side (that is, removes the pointer from the circular memory queue). The pointer references the shared memory that holds the envelope property stream, folder ID, and message ID.

  6. Drviis.dll uses the memory pointer to read the property stream from shared memory to a MailMsg object. As mentioned earlier in this section, the MailMsg object is made up of a message transfer envelope that provides the information required to route the message to the next hop, plus a pointer to the actual physical message. At this point, the MailMsg object has the message transfer envelope information because the properties for the MailMsg object are all in the shared memory block that was prepared by ExSMTP.dll.

  7. Drviis.dll places the MailMsg object in the pre-submission queue. The transport subsystem can now process the message.

  8. The advanced queuing engine triggers its transport and system events to invoke the base and Exchange categorizers and the routing engine, and other registered event sinks to process the message. Most transport processing is performed using the message transfer envelope. The message content is not opened until it is explicitly required. For example, the Exchange categorizer might have to perform a content conversion. If the message must be transferred to the next hop over SMTP, the SMTP protocol engine must access the message content in RFC 822 format.

    Note

    For local delivery of MAPI messages (sent and received on the same server without content conversion), the content is never opened by the SMTP transport components (if you have not installed any custom event sinks that attempt to read the RFC 822 message content, such as an archive sink).

  9. When the message content is opened by a component in the transport subsystem by calling the ReadContent or WriteContent method of the MailMsg object, the message content is accessed as a file similar to a message item in the \Queue folder on the file system (for example, messages that must be sent over SMTP). When messages are submitted through the Exchange store, ExIFS files are used instead of NTFS files.

  10. For messages in the Exchange store, MailMsg call Drviis.dll to open an ordinary file handle. The message content is requested in RFC 822 format. For messages that are categorized, the property stream might also contain some additional outbound conversion values that can be used to request a specific format when retrieving the content.

  11. As mentioned earlier in this section, Drviis.dll saves a pointer to the physical message in the MailMsg object. This pointer is made up of the folder ID and message ID for the message. Drviis.dll uses this pointer and any additional content formatting parameters to pass a message request packet through Epoxy.dll to Exsmtp.dll inside the Store.exe process.

  12. Exsmtp.dll calls an internal Exchange store method named EcGetMime with the folder ID and message ID to request the content of the message in RFC 822 format, specifying any additional parameters that Drviis.dll might have passed.

    Note

    You might notice the EcGetMime call in application event log entries with an event source of MSExchangeTransport and an event category of Exchange Store Driver. For an example, see Microsoft Knowledge Base article 319682, "XGEN: The Exchange 2000 Information Store Reports an Event ID327 Warning Message and Virtual Memory May Be Fragmented."

  13. Because the message was submitted through Outlook, the message is not in RFC 822 format. The message is in MAPI format, stored in the .edb file. Therefore, the content that Exsmtp.dll is requesting does not exist in the streaming database (that ExIFS is using) when the message is opened by a transport component or Internet client.

    Note

    Exchange Server 2003 stores messages received from MAPI clients, X.400 connectors, or Exchange Development Kit (EDK)-based connectors in MAPI format in the .edb database.

  14. If the message does not exist in the streaming database, it must be created using the various properties and tables in the .edb database that describe the message. Accordingly, the Exchange store uses IMAIL to create a temporary ExIFS file and to render the message from the database to that file in RFC 822 format, according to the requested formatting parameters that are passed.

    Note

    The Exchange categorizer uses the IMAIL mechanism to apply message formats to the content, as defined for Internet domains in Exchange System Manager or as specified by the user per recipient in Outlook. If no formatting parameters are passed to IMAIL, IMAIL formats MAPI messages in Summary TNEF (S/TNEF) format.

  15. In Exchange Server 2003, ExIFS.sys creates a temporary ExIFS file so that a malfunctioning event sink that attempts to modify the RFC 822 content cannot corrupt the committed pages in the streaming database. Instead of writing to actual content pages, the event sink is writing to a copy only.

  16. Once the temporary ExIFS file is generated, the file handle is passed back to Exsmtp.dll. Exsmtp.dll calls to ExIFS to retrieve a pointer to the pages that the file occupies in the streaming database (that is, to the extended attributes which ExIFS copies to an in-memory structure called a scatter list).

  17. Exsmtp.dll copies the scatter list to shared memory and passes the list back to Drviis.dll through Epoxy.dll.

  18. Drviis.dll uses this scatter list to open the ExIFS file in the form of an extended attributes (EA) file. Now that Drviis.dll has the open ExIFS file handle, it returns the file handle to MailMsg, which can then process ReadContent or WriteContent requests to the RFC 822 message content.

  19. The SMTP protocol engine can now read the message content and transfer the data to a remote host or Exchange server through SMTP.

  20. After successful message transfer, the advanced queuing engine deletes the MailMsg object, because it is no longer needed. Accordingly, the advanced queuing engine calls to the Exchange store driver (drviis.dll) to delete the message. Drviis.dll creates a request to delete the message in shared memory and transfers the request through EPOXY to Exsmtp.dll. Then Exsmtp.dll either moves the message from the sender's Outbox to the Sent Items folder or deletes the message.

Note

The content is re-rendered every time it is requested. Each time the content is requested, it is returned in a temporary ExIFS file. As long as that file remains open, it can be used. After the file is closed, it is automatically discarded, because it is only a temporary copy of the message. To minimize the number of rendering cycles, the advanced queuing engine keeps the content file open until the message is transferred or delivered. The content file is closed only when messages are ready to be deleted or are scheduled to be retried at a later time. A message might be retried at a later time either because the remote server is unavailable, or because more than 10,000 content files are open and actively processed in the queue. If more than 10,000 content files are open and actively processed, some files must be closed to make room for other messages. When a message is opened again at a later time (for example, because message transfer is retried), the content must be re-rendered. It is important to understand that IMAIL renders a new temporary ExIFS file when the file is opened. Any changes to this ExIFS file are lost when the file is closed.

Inbound Message Transfer

The Exchange store driver performs the following steps for inbound messages that must be delivered to a local recipient or the Exchange MTA.

  1. A message is placed in the pre-submission queue, either through the SMTP protocol engine or Exchange store driver, and then categorized and marked for local delivery.

  2. The advanced queuing engine triggers an SMTP StoreDriver event to signal to the Exchange Store Driver sink that a message must be transferred to the Exchange store.

  3. If the message is received through an SMTP connection or \Pickup folder, the message still resides in the \Queue folder. Accordingly, Drviis.dll calls CreateFile() to create a new file in ExIFS and copies the message item to the new file in the Exchange store.

    Note

    If messages are sent from and received in the same mailbox store, the content is not copied to the store. If messages are sent from and received in different mailbox stores on the same server, the message is copied using RFC 822 S/TNEF as the intermediate format. No content marshaling from the Exchange store to the Inetinfo process occurs. The processing is done in the Exchange store. IMAIL renders the content in S/TNEF format to an ExIFS file at the request of Exsmtp.dll. The Exchange store uses this ExIFS file to construct a new message for delivery to the mailbox store that contains the recipient's mailbox.

  4. In the SMTP/Pickup case, ExIFS returns the scatter list that indicates the location of the new item's data in the streaming database.

  5. Drviis.dll allocates memory from the shared-memory heap and places the scatter list into the allocated memory block. A pointer to that portion of allocated shared memory is then placed in the queue in the direction of the Store.exe process.

  6. ExSMTP.dll obtains the pointer from the queue on the Exchange store side. The pointer references the shared memory that holds the scatter list for the inbound message.

  7. ExSMTP.dll calls into Ifsproxy.dll with the scatter list to receive a file handle back from ExIFS. To commit the item to the database, a message must be created, so ExSMTP.dll calls to the Exchange store kernel (Store.exe) through the messaging database external interface (MDBEIF) to create a message object. ExSMTP.dll then explicitly passes the file handle of the content to the Exchange store kernel and the Exchange store kernel passes the file handle to ESE to commit the data when ExSMTP.dll commits the message object.

    Note

    Page checksums are stored in the MAPI-based database file (.edb). The streaming database file (.stm) does not contain page checksums.

  8. The Exchange store informs Outlook when a new message arrives and Outlook lists the message in the Inbox folder.

  9. ExSMTP.dll notifies Drviis.dll through EPOXY that delivery is complete, and then Drviis.dll returns a positive result to the advanced queuing engine. The advanced queuing engine can then delete the message, as follows:

    • Message was received through SMTP or the \Pickup directory   There is an .eml file in the \Queue directory for the message. The advanced queuing engine calls back to MailMsg to delete the message. Because the MailMsg object is bound to the NTFS store driver, the call is passed to NTFSDrv.dll, which deletes the message from the \Queue directory on the file system.

    • Message was submitted through the Exchange store driver   The advanced queuing engine calls back to MailMsg to delete the message. Because the MailMsg object is bound to the Exchange store driver, the call is passed to Drviis.dll, which queues an EPOXY request to ExSMTP.dll. ExSMTP.dll then either moves the message from the sender's Outbox to the Sent Items folder or deletes the message.

Note

Messages for remote recipients that arrive through \Pickup directory or SMTP protocol engine do not reach the Exchange store. They remain in the \Queue folder on the file system until they are successfully transferred to the next hop on route to their destination. However, the categorizer might use the Exchange store for messages that are not delivered through the Exchange store driver. The categorizer might need to generate delivery status notifications, which are created in the Exchange store.

Transfer Retries

Note that messages that enter the advanced queuing engine through the Exchange store driver remain in the Exchange store during the categorization and routing process, as well as during the actual transfer process. The message is not copied to the SMTP virtual server's \Queue folder. These types of messages also remain in the Exchange store if a connection failed and must be retried. If a message cannot be transferred immediately, it is moved to a temporary table. Therefore, the message disappears from the sender's Outbox folder and is copied to the Sent Items folder (if Outlook is configured to keep a copy of all messages in the Sent Items folder). The message remains in the temporary table until it is transferred successfully or expires. You can view these messages in the Failed Message Retry queue using the Queue Viewer snap-in in Exchange System Manager.