Set From, Reply-To, Return-Path, To, CC, BCC, Priority and other headers in e-mail


Introduction

MailBee.NET allows you to set any headers in the e-mail. For many headers, it also provides convenient methods to work with the header as a collection of objects, enumeration of constants, and so on. Some examples of such headers are such as To, CC, BCC, From, Importance, etc.

Header values which contain non-Latin or special characters can be automatically encoded with MailMessage.EncodeAllHeaders method. See Compose international e-mail guide for details.

Besides that, you can also work with any header value as a string to fully control how the header appears in the resulting e-mail. You can even add multiple headers with the same name (the MIME format allows this, and the typical example is "Received" headers).

This guide also explains SMTP envelopes and what differs them from message headers. The typical examples when SMTP envelopes get involved are when you send from the e-mail address different from "From" address, send to the recipients different from those specified in "To", "CC", "BCC", or request delivery confirmation.


Set different From and Return-Path (use "real" sender address different from "From" address)

Often, the sender of the e-mail ("Return-Path", "X-Sender") and its author ("From") are different e-mail addresses. The common reason for this is when you want bounce e-mails, auto-responders and other system-generated replies to your e-mail return to another address (such as bounce@domain.com) while the author's address is somewhat like newsletter@domain.com.

To explicitly specify the sender's address, use the method like Smtp.Send(string, string) and pass the sender's e-mail address as senderEmail parameter value:

Smtp mailer = new Smtp();

// For variety's sake, let's enable logging this time to remind
// that it's a very effective debug and trouble-shooting tool.
mailer.Log.Filename = @"C:\Temp\log.txt";
mailer.Log.Enabled = true;
mailer.Log.Clear();

// Use SMTP relay with authentication.
// Note that we authenticate as sender@domain.com, not as john.doe@domain.com!
mailer.SmtpServers.Add("mail.domain.com", "sender@domain.com", "secret");

// Set From address (author of the e-mail).
mailer.Message.From.AsString = "John Doe <john.doe@domain.com>";

// Set body and other headers.
mailer.Message.To.AsString = "Jane Doe <jane@company.com>";
mailer.Message.Subject = "Items for sale";
mailer.Message.BodyPlainText = "2 new items in stock";

// Send from sender@domain.com.
mailer.Send("sender@domain.com", (string)null);
Dim mailer As Smtp = New Smtp()

' For variety's sake, let's enable logging this time to remind
' that it's a very effective debug and trouble-shooting tool.
mailer.Log.Filename = "C:\Temp\log.txt"
mailer.Log.Enabled = True
mailer.Log.Clear()

' Use SMTP relay with authentication.
' Note that we authenticate as sender@domain.com, not as john.doe@domain.com!
mailer.SmtpServers.Add("mail.domain.com", "sender@domain.com", "secret")

' Set From address (author of the e-mail).
mailer.Message.From.AsString = "John Doe <john.doe@domain.com>"

' Set body and other headers.
mailer.Message.To.AsString = "Jane Doe <jane@company.com>"
mailer.Message.Subject = "Items for sale"
mailer.Message.BodyPlainText = "2 new items in stock"

' Send from sender@domain.com.
mailer.Send("sender@domain.com", CType(Nothing, String))

All samples in this guide assume MailBee, MailBee.Mime, and MailBee.SmtpMail namespaces are imported and the license key is set. See Import namespaces and set license key topic for details.

The sample above composes the message as usually. However, when transmitting the message data to the SMTP server, the client uses the explicitly specified sender's address rather than the address taken from "From" header.

The sender address is not physically a part of MIME data of an e-mail. It's a part of somewhat called SMTP envelope for an e-mail. SMTP envelope consists of a series of SMTP commands which denote the sender, the recipients, and the MIME message data. In particular, when the client submits the message to the SMTP server, it sends the sender's address in MAIL FROM command. For instance, when you do not explicitly set the sender's address, MailBee.NET issues MAIL FROM:<From@address> where From@address denotes mailer.Message.From.Email value (assuming that mailer is Smtp instance).

Why the real sender's e-mail address is often called Return-Path? The SMTP server may add this header when it receives the message from the client. In other words, Return-Path indeed denotes the real sender but only "post factum". You can examine it in the e-mails you received from the e-mail server but it won't work if you try to set it for an outgoing e-mail to specify the real sender.

There is, however, the special header X-Sender which may in part serve the purpose of setting the real sender directly in the message headers. The problem with SMTP envelopes is that they are not part of message data. For instance, if you load the message from an .EML file, you have no SMTP envelope information.

To overcome this, some e-mail systems use X-Sender header so that the e-mail address specified in X-Sender will be used as the real sender during transmitting the message to the server. This provides the method of storing SMTP envelope information in message headers. Microsoft IIS SMTP server supports this, and so MailBee.NET Queue application does.

Smtp class does not automatically try to send from X-Sender address but you can examine this header after loading the message from the file and use its value when calling Smtp.Send(string, string) method as shown in the sample code above.

 Many e-mail servers don't like when the real sender's address is not specified in the message headers. In theory, the SMTP server shouldn't even look into the MIME data and transmit it as-is. In practice, spammers often forge "From:" e-mail address and send from e-mail accounts which are not even close to what's specified in From (e.g. "From:" looks like jdoe@domain.com while real sender is somewhat like xxx34523@middleofnowhere.com).

Thus, it's recommended to include into the message yet another header (usually, Sender), which has no special meaning but just lets the SMTP server know we're not willing to hide the identify of the real sender. Adding this header is especially important if "From:" and the real sender belong to different domains.

You can add Sender header as below:

mailer.Message.Sender = "sender@domain.com";
mailer.Message.Sender = "sender@domain.com"

In some special cases, when you need to re-send the message to another address with no changes to its "From:" field (so that your recipient would see not "From:" of yours but the original "From:"), you may add Resent-From header and specify your own "From:" address there. Otherwise, the SMTP server might think that you're trying to spoof someone else's "From:" address and hide your own.


Send to undisclosed recipients (use "real" recipient addresses different from "To", "CC", "BCC" addresses)

If you just want to send e-mail to multiple recipients without disclosing their e-mail addresses to each other, you can list them in BCC. However, if your task is more specific, BCC may not always work for you.

For instance, if you want to have some recipients listed in "To:" but the e-mail should not go to them. The most typical case is when "To:" field must contain somewhat like "undisclosed recipients".

MailBee.NET can ignore To, CC, BCC values and use the explicitly specified recipients:

Smtp mailer = new Smtp();

// Use SMTP relay with authentication.
mailer.SmtpServers.Add("mail.provider.com", "jdoe@here.com", "secret");

// Set From address (will also use it as real sender's address).
mailer.Message.From.AsString = "John Doe <jdoe@here.com>";

// Set "To" but do not list any actual recipients there.
mailer.Message.To.AsString = "undisclosed recipients";

// Set other fields.
mailer.Message.Subject = "Notification";
mailer.Message.BodyPlainText = "Meet at midnight";

// Create the actual list of recipients.
EmailAddressCollection emails = new EmailAddressCollection();
emails.Add("mr.x@somewhere.com");
emails.Add("mrs.y@nowhere.com");
emails.Add("mr.z@elsewhere.com");

// Send to real recipients. We could also use comma-separated string
// of e-mail addresses rather than EmailAddressCollection object.
mailer.Send(null, emails);
Dim mailer As Smtp = New Smtp()

' Use SMTP relay with authentication.
mailer.SmtpServers.Add("mail.provider.com", "jdoe@here.com", "secret")

' Set From address (will also use it as real sender's address).
mailer.Message.From.AsString = "John Doe <jdoe@here.com>"

' Set "To" but do not list any actual recipients there.
mailer.Message.To.AsString = "undisclosed recipients"

' Set other fields.
mailer.Message.Subject = "Notification"
mailer.Message.BodyPlainText = "Meet at midnight"

' Create the actual list of recipients.
Dim emails As EmailAddressCollection = New EmailAddressCollection()
emails.Add("mr.x@somewhere.com")
emails.Add("mrs.y@nowhere.com")
emails.Add("mr.z@elsewhere.com")

' Send to real recipients. We could also use comma-separated string
' of e-mail addresses rather than EmailAddressCollection object.
mailer.Send(Nothing, emails)

When you explicitly specify recipients, MailBee.NET does not use To, CC, and BCC when submitting recipients to the SMTP server with RCPT TO commands.

The list of real recipients is the part of SMTP envelope, not of the e-mail message itself (see Set different From and Return-Path (use "real" sender address different from "From" address) topic on more details regarding SMTP envelopes). If you need to somehow keep the real recipients information in the e-mail (for instance, if you need to save the message in .EML file and then restore it from that file), you can place this information in BCC, and later read that header when loading the message from file and pass its value to Smtp.Send(string, string) method.

The above works if you have the full control over the application which sends e-mail (e.g. if you can implement reading from BCC and using that value as "real recipients list"). In case if you submit the message file to an external system like Microsoft IIS SMTP service or MailBee.NET Queue, use X-Receiver headers for that. Smtp.SubmitToPickupFolder Method(string, string, string, string, bool) method can do the job:

mailer.SubmitToPickupFolder(@"C:\Inetpub\mailroot\Pickup"nullnull, emails, true);
mailer.SubmitToPickupFolder("C:\Inetpub\mailroot\Pickup"NothingNothing, emails, True)

emails can be a comma-separated string or EmailAddressCollection object.


Set "Request delivery confirmation" and "Request read confirmation" flags

This code snippet enables MailBee.NET to notify the receiving part to send delivery and reading confirmation to the specified e-mail address:

// Set Disposition-Notification-To header.
mailer.Message.ConfirmRead = "john.doe@company.com";

// Set Return-Receipt-To header.
mailer.Message.ConfirmReceipt = "john.doe@company.com";

// Configure Delivery Status Notification (DSN).
mailer.DeliveryNotification.NotifyCondition = DsnNotifyCondition.Always;
' Set Disposition-Notification-To header.
mailer.Message.ConfirmRead = "john.doe@company.com"

' Set Return-Receipt-To header.
mailer.Message.ConfirmReceipt = "john.doe@company.com"

' Configure Delivery Status Notification (DSN).
mailer.DeliveryNotification.NotifyCondition = DsnNotifyCondition.Always

To send delivery confirmation to the specified e-mail address, the e-mail server of the receiving part must support Return-Receipt-To header.

To send reading confirmation to the specified e-mail address, the e-mail client program of the recipient must support Disposition-Notification-To header.

If the e-mail server you're relaying through and the recipient's server both support ESMTP DSN extension, you'll get delivery status notification in case if the e-mail was or wasn't delivered. This notification will be sent to "From:" address or to the actual sender address if you set it explicitly. The address specified in mailer.Message.ConfirmRead or mailer.Message.ConfirmReceipt headers is not used by DSN.

If the e-mail server also supports both Return-Receipt-To header and ESMTP DSN, you may get two delivery notifications of the same event if you enabled both options.

To learn more on how you can request reading and delivery confirmations, assign Tracking ID to each e-mail to simplify processing of bounced messages, and otherwise configure delivery notifications, refer to Request delivery and reading confirmation guide.


Set Reply-To

If you're creating an e-mail and want to specify "Reply-To:" address different from "From:" address, set mailer.Message.ReplyTo value. It's assumed that mailer is an Smtp instance and its Smtp.Message property denotes the MailMessage object to be sent.

You can also specify multiple addresses in Reply-To. To learn more, see MailMessage.ReplyTo property documentation.

The code snippet below adds two Reply-To addresses in different ways (with and without display name):

mailer.Message.ReplyTo.Add("john.doe@domain.com""John Doe");
mailer.Message.ReplyTo.Add("jane.doe@domain.com");
mailer.Message.ReplyTo.Add("john.doe@domain.com""John Doe")
mailer.Message.ReplyTo.Add("jane.doe@domain.com")

You can also specify Reply-To value as a string with mailer.Message.ReplyTo.AsString = "John Doe <jdoe@domain.com>" syntax.


Reply to message and set In-Reply-To and References headers

To reply to an existing e-mail (which you received from, let's say, IMAP or POP3 server) and make it easier for the receiving side to match the original message and its reply, do the following:

For References to work well, the other party (the recipient's mail program) must behave the same way when replying to your e-mail (i.e. it must add your e-mail's Message-ID to References of the reply e-mail).

The sample below receives the last e-mail in inbox from IMAP server, and replies it. When making the reply, the sample adds Message-ID of the original e-mail to In-Reply-To and extends References:

// Download the last e-mail from inbox.
MailMessage originalMsg = MailBee.ImapMail.Imap.QuickDownloadMessage(
    "imap.example.com", "user", "password", "Inbox", -1);

Smtp mailer = new Smtp();

// Use SMTP relay with authentication.
mailer.SmtpServers.Add("smtp.example.com", "user", "password");

// Set subject and body of the reply.
mailer.Message.Subject = "Re: " + originalMsg.Subject;
mailer.Message.BodyPlainText = "Your message was received";

// Refer the original message with In-Reply-To header.
mailer.Message.Headers["In-Reply-To"] = originalMsg.MessageID;

// Refer the entire thread with References header.
if (string.IsNullOrEmpty(originalMsg.References))
{
    mailer.Message.References = originalMsg.MessageID;
}
else
{
    mailer.Message.References = originalMsg.References +
        " " + originalMsg.MessageID;
}

// Set From address.
mailer.Message.From.Email = "john.doe@company.com";
mailer.Message.From.DisplayName = "John Doe";

// Take the recipient from the original message's "From".
mailer.Message.To.Add(originalMsg.From);

// Send the reply!
mailer.Send();
' Download the last e-mail from inbox.
Dim originalMsg As MailMessage = MailBee.ImapMail.Imap.QuickDownloadMessage( _
    "imap.example.com", "user", "password", "Inbox", -1)

Dim mailer As Smtp = New Smtp()

' Use SMTP relay with authentication.
mailer.SmtpServers.Add("smtp.example.com", "user", "password")

' Set subject and body of the reply.
mailer.Message.Subject = "Re: " + originalMsg.Subject
mailer.Message.BodyPlainText = "Your message was received"

' Refer the original message with In-Reply-To header.
mailer.Message.Headers("In-Reply-To") = originalMsg.MessageID

' Refer the entire thread with References header.
If String.IsNullOrEmpty(originalMsg.References) Then
    mailer.Message.References = originalMsg.MessageID
Else
    mailer.Message.References = originalMsg.References & _
        " " & originalMsg.MessageID
End If

' Set From address.
mailer.Message.From.Email = "john.doe@company.com"
mailer.Message.From.DisplayName = "John Doe"

' Take the recipient from the original message's "From".
mailer.Message.To.Add(originalMsg.From)

' Send the reply!
mailer.Send()

In many cases it's enough to specify just In-Reply-To header. References is more "optional" in this regard.


Set Importance, Priority, Sensitivity flags

Let's assign top priority and importance, and also mark the e-mail as confidential:

mailer.Message.Priority = MailPriority.Highest;
mailer.Message.Importance = MailPriority.Highest;
mailer.Message.Sensitivity = MailSensitivity.Confidential;
mailer.Message.Priority = MailPriority.Highest
mailer.Message.Importance = MailPriority.Highest
mailer.Message.Sensitivity = MailSensitivity.Confidential

It's assumed that mailer is an Smtp object instance and its Smtp.Message property denotes the MailMessage object to be sent.


Set custom Date and Message-ID values

By default, MailBee.NET generates Date and Message-ID values automatically when the e-mail gets sent or submitted as .EML file to MailBee.NET Queue or Microsoft IIS Pickup service.

The default Date value denotes the very moment when the message gets sent. Sometimes, you may want to correct it (e.g. specify the moment when the message was composed if you do not intend to send it immediately).

The default Message-ID value uses the computer's name in the domain part. You may wish to avoid this (e.g. use your company's domain name instead).

To achieve this, you can set Date and/or Message-ID manually and tell MailBee.NET not to generate these values automatically:

// Assign the date manually (automatic date setting
// would be DateTime.Now instead of DateTime.Today).
mailer.Message.Date = DateTime.Today;
mailer.Message.Builder.SetDateOnSend = false;

// Assign Message-ID manually (automatic setting
// would use the local computer name as domain.
mailer.Message.SetUniqueMessageID("company.com");
mailer.Message.Builder.SetMessageIDOnSend = false;
' Assign the date manually (automatic date setting
' would be DateTime.Now instead of DateTime.Today).
mailer.Message.Date = DateTime.Today
mailer.Message.Builder.SetDateOnSend = False

' Assign Message-ID manually (automatic setting
' would use the local computer name as domain.
mailer.Message.SetUniqueMessageID("company.com")
mailer.Message.Builder.SetMessageIDOnSend = False

Note that if you disabled automatic setting of Date and/or Message-ID and didn't specify them manually, the message will be sent without these headers at all. This can make sense if you wish your SMTP relay server to add these headers (some servers can do this).

For instance, if you submit e-mails to the pickup folder for later delivery, the actual e-mails can get sent hours later since they have been created. Thus, if Date is generated by MailBee.NET at the moment when the e-mail is created and put into the pickup folder, it's Date might be several hours earlier than the actual moment of sending. Some spam filters don't like this and such e-mail can be blocked.

However, if you let your SMTP relay server generate Date for your e-mails, this will occur at the very moment of sending (when the message gets processed from its pickup folder), and the Date value will be relevant.


Add custom headers

You can add your own headers to the message and to any of its parts (e.g. custom headers for attachment). You can also add multiple headers with the same name (for instance, to add new Received header in addition to those which are already in the message).

If you invent your own header, it's better to prefix its name with "X-" and use dash symbol ("-") to separate words in the name.

The sample below adds to the message a few custom headers in different ways (one of them has international characters in its value and therefore encoded). The sample also adds an attachment with custom headers:

// Add a custom header. If the header with such name already exists,
// overwrite it instead of adding another header with the same name.
mailer.Message.Headers.Add("X-Ref-ID", "8234892", true);

// Add 3 custom headers with the same name. They will form the coherent text.
mailer.Message.Headers.Add("X-Text", "Next line is in Czech", false);

// We also use international characters in 2nd header, and that's why we encode it.
string secondLineInCzech = MailMessage.GetEncodedHeaderValue(
    "X-Text", "Druhý řádek", System.Text.Encoding.UTF8, HeaderEncodingOptions.None);
mailer.Message.Headers.Add("X-Text", secondLineInCzech, false);

// Add the last X-Text header.
mailer.Message.Headers.Add("X-Text", "Its translation is \"Second line\"", false);

// Add a lengthy header to demonstrate line wrapping.
mailer.Message.Headers.Add("X-Long-Line", "This text will be wrapped " +
    "into multiple lines because it's pretty long (much longer than 76 " +
    "characters which is the recommended limit of the line length in MIME", true);

// Add a header at the top of MIME data.
mailer.Message.Headers.Add("X-Top",
    "This will appear at the top of the message source", true, 0);

// Add a custom header to the attachment.
HeaderCollection attachmentHeaders = new HeaderCollection();
attachmentHeaders.Add("Content-Hash", "2D59A090", true);
mailer.Message.Attachments.Add(@"C:\Temp\report.doc", null, null, null,
    attachmentHeaders, NewAttachmentOptions.None, MailTransferEncoding.Base64);
' Add a custom header. If the header with such name already exists,
' overwrite it instead of adding another header with the same name.
mailer.Message.Headers.Add("X-Ref-ID", "8234892", True)

' Add 3 custom headers with the same name. They will form the coherent text.
mailer.Message.Headers.Add("X-Text", "Next line is in Czech", False)

' We also use international characters in 2nd header, and that's why we encode it.
Dim secondLineInCzech As String = MailMessage.GetEncodedHeaderValue( _
    "X-Text", "Druhý řádek", System.Text.Encoding.UTF8, HeaderEncodingOptions.None)
mailer.Message.Headers.Add("X-Text", secondLineInCzech, False)

' Add the last X-Text header.
mailer.Message.Headers.Add("X-Text", "Its translation is ""Second line""", False)

' Add a lengthy header to demonstrate line wrapping.
mailer.Message.Headers.Add("X-Long-Line", "This text will be wrapped " & _
    "into multiple lines because it's pretty long (much longer than 76 " & _
    "characters which is the recommended limit of the line length in MIME", True)

' Add a header at the top of MIME data.
mailer.Message.Headers.Add("X-Top", _
    "This will appear at the top of the message source", True, 0)

' Add a custom header to the attachment.
Dim attachmentHeaders As HeaderCollection = New HeaderCollection()
attachmentHeaders.Add("Content-Hash", "2D59A090", True)
mailer.Message.Attachments.Add("C:\Temp\report.doc", Nothing, Nothing, Nothing, _
    attachmentHeaders, NewAttachmentOptions.None, MailTransferEncoding.Base64)

It's assumed that mailer is an Smtp object instance and its Smtp.Message property denotes the MailMessage object to be sent.


Send feedback to AfterLogic

Copyright © 2006-2023 AfterLogic Corporation. All rights reserved.