MailBee.NET Objects 7.1

Smtp.AddJob Method (String, String, EmailAddressCollection, DataTable, Object, Boolean, Boolean)

Puts a "mail merge over database" job onto waiting list for subsequent processing in bulk mode.

public void AddJob(
   string tag,
   string senderEmailPattern,
   EmailAddressCollection recipientsPattern,
   DataTable mergeTable,
   object mergeRowIndices,
   bool keepProducedJobs,
   bool keepMergedData
);

Parameters

tag
Any string the developer wants to assign to Tag property of SendMailJob object created by this method. The developer can leave it a null reference (Nothing in Visual Basic).
senderEmailPattern
The e-mail address template of the sender. If it's a null reference (Nothing in Visual Basic), the e-mail address template will be taken from From property.
recipientsPattern
The e-mail address template of the recipients list. If it's a null reference (Nothing in Visual Basic), the recipients list will be constructed via merge of To, Cc, and Bcc patterns with actual values from the data source.
mergeTable
The data source for mail merge.
mergeRowIndices
The comma-separated list or integer array of indices of rows of mergeTable to be processed, or a null reference (Nothing in Visual Basic) if the entire mergeTable should be processed.
keepProducedJobs
Indicates whether MailBee should create separate SendMailJob object for every e-mail message produced during mail merge. If true, JobsSuccessful and JobsFailed collections will end up with the same number of jobs as the number of e-mail messages generated; otherwise, only SendMailJob object originally added by this method will end up in JobsSuccessful or JobsFailed collections.
keepMergedData
Indicates whether MailBee should retain merged messages after they have been processed. If true, MailBee will not clear MergedXXX properties of SendMailJob object after the e-mail message associated with this object has been processed; otherwise, MailBee will clear memory occupied by the merged message so that MergedXXX properties start returning null once the message has been processed.

Remarks

This method allows the application to schedule mail merge over database for subsequent processing with SendJobs, BeginSendJobs, or SubmitJobsToPickupFolder method.

Note   To perform mail merge immediately rather than schedule it, use SendMailMerge method.

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 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.

Exceptions

Exception TypeCondition
MailBeeInvalidArgumentExceptionmergeTable is a null reference (Nothing in Visual Basic) or mergeRowIndices is invalid value (for instance, neither string nor array of integers).

Example

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.

[C#]
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:\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:\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();
            }
        }
    }
}
[Visual Basic]
Imports System
Imports System.Data
Imports System.Data.OleDb
Imports MailBee
Imports MailBee.Mime
Imports MailBee.SmtpMail

Class Sample
    ' Reports successful attempt of sending e-mail.
    Shared Sub mailer_MessageSent(ByVal sender As Object, ByVal e As SmtpMessageSentEventArgs)
        ' Display e-mail address of the successful e-mail.
        Console.WriteLine(e.MergeTable.Rows(e.MergeRowIndex)("Email") & " of '" & e.Tag & "' job SUCCEEDED")
    End Sub

    ' Reports failed attempt of sending e-mail.
    Shared Sub mailer_MessageNotSent(ByVal sender As Object, ByVal e As SmtpMessageNotSentEventArgs)
        ' Display e-mail address of the failed e-mail.
        Console.WriteLine(e.MergeTable.Rows(e.MergeRowIndex)("Email") & " of '" & e.Tag & "' job FAILED")
    End Sub

    Shared Sub Main(ByVal args() As String)
        Dim mailer As Smtp = New Smtp

        ' Logging into a file is useful for troubleshooting.
        mailer.Log.Filename = "C:\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.
        AddHandler mailer.MessageSent, AddressOf mailer_MessageSent
        AddHandler mailer.MessageNotSent, AddressOf 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).
        Dim connParams As String = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=C:\Newsletter.mdb;"

        ' Indices of the data rows which failed during the first run.
        ' If null, all indices will be processed.
        Dim failedIndices As String = Nothing

        Dim table As DataTable = Nothing

        ' 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.
        Dim i As Integer
        For i = 0 To 1
            ' Connect to the database and populate mail merge job to-do list with
            ' the data from "mailing_list" table.
            Dim conn As OleDbConnection
            Try
                conn = New OleDbConnection(connParams)

                ' Open the connection and get the data.
                Dim command As OleDbCommand = New OleDbCommand("SELECT * FROM mailing_list", conn)
                conn.Open()
                Dim adapter As OleDbDataAdapter = 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", Nothing, table, failedIndices, True, False)
            Finally
                If Not conn Is Nothing Then
                    conn.Close()
                End If
            End Try

            ' 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 Then
                Console.WriteLine("All of the rows of the table have been processed and sent as e-mails.")
                Exit For
            Else
                If mailer.JobsSuccessful.Count = 0 Then
                    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"))
                End If
                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()
            End If
        Next
    End Sub
End Class

See Also

Smtp Class | MailBee.SmtpMail Namespace | Smtp.AddJob Overload List | RetryFailedJobs | SendMailMerge