Simple Mail Transfer Protocol  
 

The Simple Mail Transfer Protocol (SMTP) enables applications to deliver email messages to one or more recipients. The library provides an API for addressing and delivering messages, and extended features such as user authentication and delivery status notification. This library is typically used in conjunction with the Mail Message library to create the messages, and the Domain Name Service library to determine what servers are responsible for accepting mail for a specific user.

Mail Exchanges

When a message is delivered to a user, the application must determine what mail server is responsible for accepting messages for that user. This can be accomplished using the Domain Name Services (DNS) protocol, a protocol that is most commonly used to resolve host names such as www.microsoft.com into Internet addresses. This is typically accomplished by sending a request to a nameserver, a computer system that provides domain name services. In addition to resolving host names, nameservers can also provide information about those servers which are responsible for accepting mail for a given domain. There can be multiple servers which process mail for a domain with each server assigned a priority as part of their mail exchange (MX) record. If there is no mail exchange record for a domain, then the domain name itself is used.

To deliver a message directly to the recipient, you must examine the recipient address and request the list of mail exchanges for that user's domain. Using the DNS API, this is done by calling the DnsEnumMailExchanges function. If the recipient address is joe@example.com, you would want to enumerate the mail exchanges for the example.com domain. This will give you the name of the servers that will accept mail for users in that domain. For example, the function may return the host name mail.example.com as the name of the server which will accept mail for users in the example.com domain. Note that it is possible that one or more of the mail exchanges for a domain may not be in the recipient domain itself. In other words, it is possible that smtp.othercorp.net could be returned as a mail exchange for example.com. This is frequently the case when another organization is forwarding mail for that domain.

Therefore, there are three general steps that you must take when delivering mail directly to the recipient:

  1. Parse the address of each recipient in the message. If you are using the MIME API, the MimeEnumMessageRecipients function can be helpful in extracting all of the recipient addresses. Everything after the atsign (@) in the address is the domain portion of that address.
  2. Perform an MX record lookup using the DNS API function DnsEnumMailExchanges and specifying the recipient's domain. The function will return the name of the servers responsible for accepting mail for that user. If there are more than one server, they will be returned in order of their relative priority, with the highest priority server being returned first. This means that you should attempt to connect to those servers in the order that they are returned by the function.
  3. Attempt to connect to the first server returned by the DnsEnumMailExchanges function. The connection should be on the default port, and you should not attempt to use any authentication. If the server accepts the connection, then use the SmtpSendMessage function to deliver the message. If the connection is rejected or the message is not accepted, attempt to connect to the next mail exchange server until all servers have been tried.
  4. If no mail exchange servers were returned by DnsEnumMailExchanges, or you could not connect to any of them, attempt to connect to the domain specified in the address using the default port. If the connection succeeds, then deliver the message. If you cannot connect or the message is not accepted, then report to the user that the message could not be delivered.

One last important consideration is that many Internet Service Providers now block outbound connections on port 25 to any mail servers other than their own. If you are unable to establish any connections, either with the error that the connection was refused or it consistently times out, contact your ISP to determine if port 25 is being blocked as an anti-spam measure. If this is the case, it will be required that you relay all messages through their mail servers or use an alternate port number.

Relay Servers

In some situations it may not be possible to send mail directly to the server that accepts mail for a given domain. The two most common situations are corporate networks which have centralized servers that are responsible for delivering and forwarding messages, or an Internet Service Provider (ISP) which specifically blocks access to all mail servers other than their own. This is usually done as either a security measure or as a means to inhibit users from sending unsolicited commercial email messages. If the standard SMTP port is being blocked, then any connection attempts will either fail immediately with an error that the server is unreachable, or the connections will simply time-out. In either case, a relay server must be specified in order to send email messages.

A relay server is a system which will accept messages addressed to users who may be in a different domain, and will relay those messages to the appropriate server that does accept mail for the domain. Using a relay server is generally easier than sending messages directly to the recipient. In order to send a message through a relay, you need to perform the following steps:

  1. Connect to the relay server as you would normally.
  2. Authenticate the client to the server. This may or may not be required, depending on how the server is configured. Some servers may be configured to only require authentication if you are connecting from an IP address that is not recognized as part of that system's network, for example, if you are connecting using a different Internet Service Provider. Others may always require authentication. Check with the server administrator if necessary to determine if and when authentication is required.
  3. Use the SmtpSendMessage function to deliver the message to the recipients through the relay server. If there are multiple recipients, you can use the MIME API to enumerate the recipient addresses and then pass them to the SmtpSendMessage function.

It is important to note that using a mail server as a relay without the permission of the organization or individual who owns that server may violate Acceptable Use Policies and/or Terms of Service agreements with your service provider. Systems which relay messages from anyone, regardless of whether the message is coming from a recognized domain, are called open relays. Because open relays are often used to send unsolicited email, many administrators block mail that comes from one. It is recommended that users check with their network administrators or Internet service providers to determine if access to external mail servers is restricted and what is the acceptable use policy for relaying messages through their mail servers.

The first step your application must take is to initialize the library, then establish a connection to the server and authenticate the client if necessary. The following functions are available for use by your application:

SmtpInitialize
Initialize the library and load the Windows Sockets library for the current process. This must be the first function call that the application makes before calling the other SMTP API functions.

SmtpConnect
Establish a connection to the SMTP server. This function will return a handle to a client session which is used in subsequent calls to the SMTP API.

SmtpAuthenticate
Authenticate the client session to the server using a username and password. This function should be called immediately after the connection has been established to the server. This is typically required if you are attempting to use the mail server as a relay, asking it to forward the message on to the server that actually accepts email for the recipient. Many Internet Service Providers (ISPs) require that users authenticate prior to sending mail through their servers. You may need to contact the server administrator to determine if authentication is required.

SmtpDisconnect
Disconnect from the SMTP server and release any resources that have been allocated for the client session. After this function is called, the client handle is no longer valid.

SmtpUninitialize
Unload the Windows Sockets library and release any resources that have been allocated for the current process. This is the last function call the application should make prior to terminating.

Message Delivery

There are two general methods that can be used to deliver messages through the mail server. In most cases, it can be done with a single function call. However, there are some circumstances where it would be more appropriate to perform the transaction in stages. The SMTP API supports both methods.

SmtpSendMessage
This is the simplest method for sending an email message through the server. You provide the sender and recipient addresses, along with the message contents and the function will submit the message to the server for delivery.

SmtpCreateMessage
This function begins a transaction in which a message is dynamically composed, addressed and delivered in stages. You provide the sender address and message size to this function, and after it returns you begin the next stage, which is addressing the message.

SmtpAddRecipient
This function adds a recipient address to the recipient list for the message. This should be called once for each recipient, as well as for any recipients who are to receive "blind copies" of the message. A blind copy is when the message is sent to a recipient, but that recipient's address is not listed in any of the headers of the message; the other recipients will be unaware that the message was delivered to him. Most servers have a limit of approximately 100 recipients per message. It is possible that this function will return an error for a specific recipient address; the address may be malformed or it may not be acceptable for some other reason. This does not mean that the message will be rejected in its entirety, only that the specified recipient is not acceptable.

SmtpAppendMessage
This function should be called after all of the recipients have been added. It is used to send the contents of the message to the server. It is also possible to use the lower level SmtpWrite function to send data directly to the server, however SmtpAppendMessage is generally easier to use and can write data from memory, the system clipboard or from a file on disk.

SmtpCloseMessage
This function is called after the entire message has been sent to the server. This terminates the transaction and the message is submitted for delivery. Note that it is possible for the server to accept the message up to this point and then reject it at this final step due to some restriction, such as the message being too large.