SmtpAddJob Method (String, String, EmailAddressCollection, DataTable, Object, Boolean, Boolean) |
Namespace: MailBee.SmtpMail
public void AddJob( string tag, string senderEmailPattern, EmailAddressCollection recipientsPattern, DataTable mergeTable, Object mergeRowIndices, bool keepProducedJobs, bool keepMergedData )
Exception | Condition |
---|---|
MailBeeInvalidArgumentException | mergeTable is a null reference (Nothing in Visual Basic) or mergeRowIndices is invalid value (for instance, neither string nor array of integers). |
This method allows the application to schedule mail merge over database for subsequent processing with SendJobs, BeginSendJobs(AsyncCallback, Object), or SubmitJobsToPickupFolder(String, Boolean) method.
Note |
---|
To perform mail merge immediately rather than schedule it, use SendMailMerge(String, EmailAddressCollection, DataTable) method. |
Note |
---|
This method is not available in .NET Core and UWP editions. |
The mail merge requirements:
mergeRowIndices parameter can be used to specify which rows of mergeTable should be processed. For instance, consider the following scenario: the application initially performed the mail merge with not 100% positive results (some e-mails failed to be sent), and it's desired to run it again to try to re-send initially failed e-mails. This can be done with RetryFailedJobs method but this requires calling RetryFailedJobs in the same application instance that was used to run the initial mail merge. If the initial instance of the application shuts down after performing mail merge, the application should save failed data row indices in a persistent storage (database, file, etc) on exit, and then load these data row indices back when another instance of the application starts. See the example below for details.
keepProducedJobs parameter controls what to do with SendMailJob objects created during mail merge process. When a mail merge job is submitted to JobsPending collection, this job represents the entire mail merge task. Once processing of this job starts, MailBee "bites" a single data row index from this job and creates new SendMailJob object for the e-mail template and this data row. The original mail merge job is moved into JobsRunning (and then into JobsSuccessful or JobsFailed) only when a single data row remains in it. Thus, MailBee splits large mail merge job into many smaller jobs (each processes a single data row) during processing. This allows the developer to easily monitor the status of each e-mail produced by mail merge process and otherwise manage mail merge processing on per e-mail level. However, if the application does not need this, it may set keepProducedJobs to false to automatically remove SendMailJob objects created during processing mail merge when they are no longer needed. This way, only the original SendMailMerge(String, EmailAddressCollection, DataTable) object will be put in JobsSuccessful or JobsFailed collections once the mail merge has been finished. This object will refer to the last data row and the last e-mail message generated during mail merge process.
As you can see, when keepProducedJobs is false, the last sub-job matches so that overall number of items in all collections like JobsPending, JobsFailed, and JobsFailed won't change, the items will just be moved among these collections.
You can also manually control whether to keep jobs after processing with FinishingJob event. For instance, you can make MailBee remove even those jobs which haven't been created by mail merge process (so that total number of all items in all jobs collections upon completion will be zero). This can be useful for the optimization of memory use.
keepMergedData parameter can be set to true to tell MailBee not to clear memory occupied by e-mails generated during mail merge. However, this may cause out-of-memory issues if the size of each generated e-mail message or their number was large.
Still, if's safe to set keepMergedData to true if keepProducedJobs is false. In this case, only a single SendMailJob object will be added to JobsSuccessful or JobsFailed collections so that only a single merged e-mail message will reside in memory.
If, for some reason, you need to retain all the e-mails sent (or not sent) during mail merge, the best approach is to subscribe to MessageSent and MessageNotSent events and perform what you need in the event handlers. Even if keepMergedData is false, MailBee won't clear memory occupied by generated e-mails until MessageSent and MessageNotSent have been raised.
The above is true for keepProducedJobs parameter as well. E-mails generated during mail merge won't be discarded until MailBee has raised MessageSent and MessageNotSent (or any other events which occur before MessageSent or MessageNotSent).
If the application hasn't subscribed to any of these events (and keepProducedJobs or keepMergedData is false), MailBee will dispose objects which are no longer necessary when appropriate.
This console sample performs mail merge in two runs. On the second run, all the data rows which failed to be sent out as e-mail messages on the first run are tried again. The application may complete in a single run if all the data rows have been successfully sent as e-mails within the first run.
This sample does NOT use RetryFailedJobs method to put failed jobs back into the pending queue. Instead, it demonstrates the approach which would allow the application to terminate after the first run and then retry mail merge of failed data rows later in a separate run of the application. In this sample both runs actually occur within a single application instance but the application structure is ready for making every run occur within separate instances. The sample shows how to get the list of failed data rows into a string and then load it from a string. In a real application, this string will be saved in a file or database before the application terminates first time, and then loaded back from this file or database when the application starts again next time.
using System; using System.Data; using System.Data.OleDb; using MailBee; using MailBee.Mime; using MailBee.SmtpMail; class Sample { // Reports successful attempt of sending e-mail. static void mailer_MessageSent(object sender, SmtpMessageSentEventArgs e) { // Display e-mail address of the successful e-mail. Console.WriteLine(e.MergeTable.Rows[e.MergeRowIndex]["Email"] + " of '" + e.Tag + "' job SUCCEEDED"); } // Reports failed attempt of sending e-mail. static void mailer_MessageNotSent(object sender, SmtpMessageNotSentEventArgs e) { // Display e-mail address of the failed e-mail. Console.WriteLine(e.MergeTable.Rows[e.MergeRowIndex]["Email"] + " of '" + e.Tag + "' job FAILED"); } static void Main(string[] args) { Smtp mailer = new Smtp(); // Logging into a file is useful for troubleshooting. mailer.Log.Filename = @"C:\Temp\log.txt"; mailer.Log.Enabled = true; mailer.Log.Format = LogFormatOptions.AddContextInfo; mailer.Log.Clear(); // Uncomment the line below to use unlimited number of worker threads (up to 60) // and increase performance. Note that not all SMTP servers support this. // mailer.MaxThreadCount = -1; // Subscribe to events to track send bulk mail progress. mailer.MessageSent += new SmtpMessageSentEventHandler(mailer_MessageSent); mailer.MessageNotSent += new SmtpMessageNotSentEventHandler(mailer_MessageNotSent); // Setup SMTP server parameters. mailer.SmtpServers.Add("mail.domain.com", "jdoe", "secret"); // Setup e-mail message header template for mail merge. mailer.Message.From.AsString = "John Doe <john.doe@domain.com>"; mailer.Message.To.AsString = "##Name## <##Email##>"; mailer.Message.Subject = "Our Jan/2007 newsletter"; // Setup DSN template for mail merge. In particular, this can be useful // to track bounced messages which may come back from some addresses after // sending bulk mail out. If the SMTP server does not support DSN, this // setting will be ignored. mailer.DeliveryNotification.TrackingID = "Jan2007_##ID##"; // Setup HTML body template. mailer.Message.BodyHtmlText = "<html>##Body##</html>"; // Setup template for adding file attachments upon the specified path. // In this sample, the path to attachment files will be constructed as // "C:\" + DatabaseRecordField("Doc_path"). mailer.Message.Merge.AddAttachmentPattern(@"C:\##Doc_path##"); // Make outgoing e-mails UTF-8 to allow content in any language. mailer.Message.Charset = "UTF-8"; // Tell MailBee to generate alternative plain-text version // of each e-mail automatically. mailer.Message.Builder.HtmlToPlainMode = HtmlToPlainAutoConvert.IfHtml; // Specify database connection string (it may be different in your case). string connParams = @"Provider=Microsoft.Jet.OLEDB.4.0; Data Source=C:\Temp\newsletter.mdb;"; // Indices of the data rows which failed during the first run. // If null, all indices will be processed. string failedIndices = null; DataTable table = null; // Make two runs of mail merge. If e-mails created from some data rows fail, // we'll attempt to resend them on the second run. for (int i = 0; i < 2; i++) { // Connect to the database and populate mail merge job to-do list with // the data from "mailing_list" table. using (OleDbConnection conn = new OleDbConnection(connParams)) { // Open the connection and get the data. OleDbCommand command = new OleDbCommand("SELECT * FROM mailing_list", conn); conn.Open(); OleDbDataAdapter adapter = new OleDbDataAdapter(); table = new DataTable(); adapter.SelectCommand = command; adapter.Fill(table); // Create a job which is the following task for MailBee: perform mail merge over // the specified data table and send out each resulting e-mail to // the recipients which appear in the resulting messages. "bounce@domain.com" // address will be used as Return-Path (i.e. sender e-mail address). mailer.AddJob("My", "bounce@domain.com", null, table, failedIndices, true, false); } // Run the job. The actual mail merge takes place here. mailer.SendJobs(); Console.WriteLine(); // Report results (row indices in the data table) to the console. if (mailer.JobsFailed.Count == 0) { Console.WriteLine("All of the rows of the table have been processed and sent as e-mails."); break; } else { if (mailer.JobsSuccessful.Count == 0) { Console.WriteLine("None of the rows of the table has been processed and sent as e-mail."); } else { Console.WriteLine("Not all rows of the table have been processed and sent as e-mails."); Console.WriteLine(); Console.WriteLine("Successful rows: "); Console.WriteLine(mailer.JobsSuccessful.GetIndicesAsString(table, "My")); Console.WriteLine(); Console.WriteLine("Failed rows: "); Console.WriteLine(mailer.JobsFailed.GetIndicesAsString(table, "My")); } Console.WriteLine(); // Remember failed data rows and clean-up the collections of the results. // Actually, we could simply call mailer.RetryFailedJobs instead. We're using // 'failedIndices = mailer.JobsFailed.GetIndicesAsString' to demonstrate // how this could be done if the application terminates after the first run and // then starts again for the second run (which retries processing the failed // data rows). In this case, we need to somehow pass the list of failed data rows // between two instances of the application. To accomplish this, failedIndices can // be written into a file in the end of the first run of the app and then read from // the file in the beginning of the second run. failedIndices = mailer.JobsFailed.GetIndicesAsString(table, "My"); mailer.JobsSuccessful.Clear(); mailer.JobsFailed.Clear(); } } } }