Smtp object provides lots of events you can subscribe to. This gives you a great control over the entire process how the message is sent.
You can track every byte being transmitted over the network and every step of the connection, alter the e-mail being sent just before it gets submitted to the server (useful for mail merge), and so on.
Some events of Smtp object mainly make sense for bulk sending mode when multiple e-mails get sent within a single method call. They are MergingMessage, SendingMessage, MessageSent, MessageNotSent,SubmittingMessageToPickupFolder, MessageSubmittedToPickupFolder, and FinishingJob .
It should be also stated that MailBee.NET provides a protected On<EventName> method for every event. This allows you to derive your own class from Smtp class and implement your own handlers for events. This can be useful in some special cases such as handling events when the message loop thread is blocked (can happen in desktop applications). See Smtp.OnConnected method documentation for details.
This console sample subscribes to a few events to control the key points of the SMTP session: establishing the connection, submitting the sender and every recipient, the upload progress of the message data:
using System; using MailBee; using MailBee.Mime; using MailBee.SmtpMail; class Sample { private static void OnConnected(object sender, ConnectedEventArgs e) { Console.WriteLine("The server accepted the connection."); } private static void OnSenderOK(object sender, SmtpMessageSenderSubmittedEventArgs e) { Console.WriteLine(e.SenderEmail + " accepted as sender."); } private static void OnRecipientOK(object sender, SmtpMessageRecipientSubmittedEventArgs e) { Console.WriteLine(e.RecipientEmail + " accepted as recipient"); } private static void OnDataChunkSent(object sender, SmtpMessageDataChunkSentEventArgs e) { Console.WriteLine(string.Format("{0} of {1} bytes sent", e.TotalBytesSent.ToString(), e.DataTotalLength.ToString())); } static void Main(string[] args) { Smtp mailer = new Smtp(); // Use SMTP relay server with authentication. mailer.SmtpServers.Add("mail.here.com", "john.doe", "secret"); // Set From, To and CC as strings (with friendly names). mailer.Message.From.AsString = "John Doe <john.doe@here.com>"; mailer.Message.To.AsString = "Jane Doe <jane.doe@there.com>"; mailer.Message.Cc.AsString = "John Smith <j.smith@elsewhere.com>"; mailer.Message.Subject = "Test message"; mailer.Message.BodyPlainText = "This is a test message"; // Subscribe to events. mailer.Connected += new ConnectedEventHandler(OnConnected); mailer.MessageSenderSubmitted += new SmtpMessageSenderSubmittedEventHandler(OnSenderOK); mailer.MessageRecipientSubmitted += new SmtpMessageRecipientSubmittedEventHandler(OnRecipientOK); mailer.MessageDataChunkSent += new SmtpMessageDataChunkSentEventHandler(OnDataChunkSent); mailer.Send(); } }
Imports System Imports MailBee Imports MailBee.Mime Imports MailBee.SmtpMail Module Module1 Private Sub OnConnected(ByVal sender As Object, _ ByVal e As ConnectedEventArgs) Console.WriteLine("The server accepted the connection.") End Sub Private Sub OnSenderOK(ByVal sender As Object, _ ByVal e As SmtpMessageSenderSubmittedEventArgs) Console.WriteLine(e.SenderEmail + " accepted as sender.") End Sub Private Sub OnRecipientOK(ByVal sender As Object, _ ByVal e As SmtpMessageRecipientSubmittedEventArgs) Console.WriteLine(e.RecipientEmail + " accepted as recipient") End Sub Private Sub OnDataChunkSent(ByVal sender As Object, _ ByVal e As SmtpMessageDataChunkSentEventArgs) Console.WriteLine(String.Format("{0} of {1} bytes sent", _ e.TotalBytesSent.ToString(), _ e.DataTotalLength.ToString())) End Sub Sub Main() Dim mailer As Smtp = New Smtp() ' Use SMTP relay server with authentication. mailer.SmtpServers.Add("mail.here.com", "john.doe", "secret") ' Set From, To and CC as strings (with friendly names). mailer.Message.From.AsString = "John Doe <john.doe@here.com>" mailer.Message.To.AsString = "Jane Doe <jane.doe@there.com>" mailer.Message.Cc.AsString = "John Smith <j.smith@elsewhere.com>" mailer.Message.Subject = "Test message" mailer.Message.BodyPlainText = "This is a test message" ' Subscribe to events. AddHandler mailer.Connected, AddressOf OnConnected AddHandler mailer.MessageSenderSubmitted, AddressOf OnSenderOK AddHandler mailer.MessageRecipientSubmitted, AddressOf OnRecipientOK AddHandler mailer.MessageDataChunkSent, AddressOf OnDataChunkSent mailer.Send() End Sub End Module
The samples throughout this guide assume that MailBee.NET SMTP license key is already set. See Import namespaces and set license key topic for details.
MergingMessage, SendingMessage and SubmittingMessageToPickupFolder events of Smtp object allow you to pre-process the e-mail before it gets sent (in case of MergingMessage, before the e-mail is created from the template).
Consider the following mail merge scenario. You've set the template and the data source and started the mail merge process. For every row of the data source, mail merge procedure generates an e-mail and sends it. All is great until you find out that you need to "touch" every message a bit.
When sending a single e-mail, you can fine-tune it as you need before calling Smtp.Send method. But during mail merge all e-mails get generated automatically. In this case, you can use SendingMessage event. This will work with a single e-mail as well.
The console sample below performs mail merge and uses SendingMessage event to sign every outgoing message with a DKIM signature:
using System; using System.Data; using System.IO; using MailBee; using MailBee.Mime; using MailBee.SmtpMail; using MailBee.Security; class Sample { private static void OnSendingMessage(object sender, SmtpSendingMessageEventArgs e) { // Sign each outgoing e-mail with DKIM signature. e.MailMessage.DomainKeysSign( false, null, privateKey, false, "dk", DomainKeysTypes.DKIM); } static string privateKey = null; static void Main(string[] args) { // Describe the data source for the mail merge. // In real apps, you'll connect to the database. DataTable workTable = new DataTable("customers"); DataColumn workCol = workTable.Columns.Add("id", typeof(int)); workCol.AllowDBNull = false; workCol.Unique = true; workTable.Columns.Add("name", typeof(string)); workTable.Columns.Add("email", typeof(string)); // Add two rows to the data source. This way, the mail merge // procedure will generate two e-mails. DataRow row = workTable.NewRow(); row["id"] = 1; row["name"] = "John Doe"; row["email"] = "john.doe@company.com"; workTable.Rows.Add(row); row = workTable.NewRow(); row["id"] = 2; row["name"] = "Bob Brown"; row["email"] = "bob.brown@example.com"; workTable.Rows.Add(row); // To avoid re-reading private key for each message, // we read it once and then use memory copy. privateKey = File.ReadAllText(@"C:\Temp\rsa512.private"); Smtp mailer = new Smtp(); // Use SMTP relay server with authentication. mailer.SmtpServers.Add("mail.here.com", "jane.doe", "secret"); // Set static From and Subject. mailer.Message.From.AsString = "Jane Doe <jane.doe@here.com>"; mailer.Message.Subject = "Greetings"; // Set templates for To and body. mailer.Message.To.AsString = "##name## <##email##>"; mailer.Message.BodyPlainText = "Message for ##name##"; // Subscribe to SendingMessage event. mailer.SendingMessage += new SmtpSendingMessageEventHandler(OnSendingMessage); // Generate and send e-mails. mailer.SendMailMerge(null, null, workTable); } }
Imports System Imports System.Data Imports System.IO Imports MailBee Imports MailBee.Mime Imports MailBee.SmtpMail Imports MailBee.Security Module Module1 Private Sub OnSendingMessage(ByVal sender As Object, _ ByVal e As SmtpSendingMessageEventArgs) ' Sign each outgoing e-mail with DKIM signature. e.MailMessage.DomainKeysSign(False, Nothing, privateKey, _ False, "dk", DomainKeysTypes.DKIM) End Sub Private privateKey As String = Nothing Sub Main() ' Describe the data source for the mail merge. ' In real apps, you'll connect to the database. Dim workTable As New DataTable("customers") Dim workCol As DataColumn = _ workTable.Columns.Add("id", GetType(Integer)) workCol.AllowDBNull = False workCol.Unique = True workTable.Columns.Add("name", GetType(String)) workTable.Columns.Add("email", GetType(String)) ' Add two rows to the data source. This way, the mail merge ' procedure will generate two e-mails. Dim row As DataRow = workTable.NewRow() row("id") = 1 row("name") = "John Doe" row("email") = "john.doe@company.com" workTable.Rows.Add(row) row = workTable.NewRow() row("id") = 2 row("name") = "Bob Brown" row("email") = "bob.brown@example.com" workTable.Rows.Add(row) ' To avoid re-reading private key for each message, ' we read it once and then use memory copy. privateKey = File.ReadAllText("C:\Temp\rsa512.private") Dim mailer As Smtp = New Smtp() ' Use SMTP relay server with authentication. mailer.SmtpServers.Add("mail.here.com", "jane.doe", "secret") ' Set static From and Subject. mailer.Message.From.AsString = "Jane Doe <jane.doe@here.com>" mailer.Message.Subject = "Greetings" ' Set templates for To and body. mailer.Message.To.AsString = "##name## <##email##>" mailer.Message.BodyPlainText = "Message for ##name##" ' Subscribe to SendingMessage event. AddHandler mailer.SendingMessage, AddressOf OnSendingMessage ' Generate and send e-mails. mailer.SendMailMerge(Nothing, Nothing, workTable) End Sub End Module
In any event handler (or in any thread), you can call mailer.Abort
to immediately close the connection (mailer
denotes Smtp instance which raised this event).
"Any event handler" is not limited to "any MailBee.NET event handler". For instance, you can call mailer.Abort
in Form_Closing
event handler of your main form (this will abort MailBee.NET immediately when the user closes the application). Just make sure you declared mailer
on the global level so that Form_Closing
could access it.
Also, MergingMessage, SendingMessage and SubmittingMessageToPickupFolder events of Smtp object allow you to skip the particular message but continue to subsequent messages.
With MessageRecipientSubmitted event, you can cancel the sending process in case if the e-mail address of a certain important recipient gets rejected by the SMTP server. See Use events to track successful and failed recipients during sending e-mail topic for details.
And there is Smtp.StopJobs method (can be used with mail merge or whenever you send bulk mail). It stops bulk mail process more gracefully than Smtp.Abort because it first completes sending of the e-mail currently being sent and simply does not continue processing other pending e-mails.
The code snippet below contains the handler of SendingMessage event, which skips messages if they are greater than 100KB in size. It also aborts the entire process if certain external variable aborted
becomes true:
using System; using MailBee; using MailBee.SmtpMail; class Sample { static bool aborted = false; static Smtp mailer = new Smtp(); static void OnSendingMessage(object sender, SmtpSendingMessageEventArgs e) { if (aborted) { mailer.Abort(); } else if (e.MailMessage.Size > 1024 * 100) { e.SendIt = false; } } static void Main(string[] args) { // Attach event handler. mailer.SendingMessage += new SmtpSendingMessageEventHandler(OnSendingMessage); // The rest of your code... } }
Imports System Imports MailBee Imports MailBee.SmtpMail Module Module1 Private aborted As Boolean = False Private mailer As New Smtp() Sub OnSendingMessage(ByVal sender As Object, _ ByVal e As SmtpSendingMessageEventArgs) If aborted Then mailer.Abort() Else If e.MailMessage.Size > 1024 * 100 Then e.SendIt = False End If End If End Sub Sub Main() ' Attach event handler. AddHandler mailer.SendingMessage, AddressOf OnSendingMessage ' The rest of your code... End Sub End Module
We assume the main code uses mailer
object to send bulk mail and sets aborted
to true when it wants MailBee.NET not to send any more messages and close the connection.
It's understood that the connection won't be closed immediately when you set aborted to true. OnSendingMessage
handler will be able to respond to this only when SendingMessage event gets raised. If you want to abort the connection immediately, call mailer.Abort
.
Copyright © 2006-2024 AfterLogic Corporation. All rights reserved.