Table of Contents


EmailManager Class Reference

Overview

The EmailManager class provides a comprehensive API for sending emails through the platform. It handles email construction and attachment management.

EmailManager implements IDisposable and should always be used within a using statement to ensure proper resource cleanup.

using (var emailManager = new EmailManager())
{
    // Email operations here
}

Core Concepts

Email Templates

Email templates define reusable message structures with merge fields. Templates can be:

  • Text: Plain text emails
  • HTML: Rich HTML emails with inline styling
  • Active Page: Dynamic template-based emails

Templates support merge fields that are populated from model objects and optional data bags during email construction.

Message Construction

Emails are constructed using the MailMessage class from System.Net.Mail. The EmailManager provides methods to:

  • Create messages from templates
  • Attach files from various sources
  • Configure recipients, subject, and body content

Attachments

Attachments can be added from:

  • Byte arrays
  • Streams
  • Document IDs (referencing platform documents)
⚠️ Warning: Document attachments cannot reference YouTube/Vimeo videos or links.

Classes & Methods

EmailManager Class

Constructors

ConstructorDescription
EmailManager()Creates a new instance of EmailManager class

Methods

Method & SignatureReturn TypeDescription
AttachFile(MailMessage message, string documentId)voidConstructs and adds an attachment from a Document to the outbound MailMessage. The document type cannot be a YouTube/Vimeo Video or Link.
AttachFile(MailMessage message, string name, byte[] fileBytes)voidConstructs and adds an attachment from an array of bytes to the outbound MailMessage.
CreateAttachment(string documentId)AttachmentConstructs an attachment from a Document, which can be added to the outbound MailMessage. The document type cannot be a YouTube/Vimeo Video or Link.
CreateAttachment(string name, byte[] fileBytes)AttachmentConstructs an attachment from an array of bytes, which can be added to the outbound MailMessage.
CreateEmail(EmailTemplate template, object model, Dictionary<string,object> dataBag)MailMessageStatic method. Constructs a single outbound email object from the specified template, which can be further customized before sending out. Model and DataBag objects are used for serving the merge fields within the template Subject and Body. DataBag argument is optional.
CreateEmail(string templateId, object model, Dictionary<string,object> dataBag)MailMessageStatic method. Constructs a single outbound email object from the specified template, which can be further customized before sending out. Model and DataBag objects are used for serving the merge fields within the template Subject and Body. DataBag argument is optional.
SendEmail(MailMessage message)voidSends an outbound email using the MailMessage.
SendEmail(string to, string subject, string message)voidSends an outbound email to the email address provided.
SendEmails(List<MailMessage> messages)voidSends one or more outbound emails using the list of MailMessages.

Method Details

AttachFile (MailMessage, string documentId)

Constructs and adds an attachment from a Document to the outbound MailMessage.

Parameters:

  • message (MailMessage) - The email message to attach the file to
  • documentId (string) - The ID of the document to attach

Returns:

  • void

Description:

This method retrieves a document from the platform by its ID, converts it to an attachment, and adds it to the specified MailMessage. The document type cannot be a YouTube/Vimeo Video or Link.

The method automatically handles document retrieval, byte conversion, and attachment creation. If the document cannot be found or is an invalid type, a ValidationException is thrown.

Usage Example:

var emailTemplate = Database.Query<EmailTemplate>()
    .Where(a => a.Name == "New Price List Alert")
    .First();

var user = SystemInfo.UserInfo;

// Locate the Document to attach
var doc = Database.Query<Document>()
    .Where(a => a.Name == "2014 Price List.pdf")
    .First();

// Send the email with attachment
using (var emailManager = new EmailManager())
{
    var message = EmailManager.CreateEmail(emailTemplate, user);
    message.To.Add(new System.Net.Mail.MailAddress(user.Email, user.Name));
    
    emailManager.AttachFile(message, doc.Id);
    
    emailManager.SendEmail(message);
}
⚠️ Warning: The document type cannot be a YouTube/Vimeo Video or Link. Attempting to attach these types will result in a ValidationException.
💡 Note: The document must exist in the platform and the current user must have access to retrieve it.

AttachFile (MailMessage, string name, byte[] fileBytes)

Constructs and adds an attachment from an array of bytes to the outbound MailMessage.

Parameters:

  • message (MailMessage) - The email message to attach the file to
  • name (string) - The filename for the attachment
  • fileBytes (byte[]) - The file content as a byte array

Returns:

  • void

Description:

This method creates an attachment from a byte array with the specified filename and adds it directly to the MailMessage. This is useful when you have file content in memory or have generated content programmatically.

If the name parameter is null or empty, the method automatically generates a filename in the format attachment_N where N is the current attachment count plus one.

Usage Example:

// Generate a report as bytes
byte[] reportBytes = GenerateMonthlyReport();

using (var emailManager = new EmailManager())
{
    var message = new System.Net.Mail.MailMessage();
    message.From = new System.Net.Mail.MailAddress("sender@example.com");
    message.To.Add("recipient@example.com");
    message.Subject = "Monthly Report";
    message.Body = "Please see the attached monthly report.";
    
    // Attach the byte array as a file
    emailManager.AttachFile(message, "MonthlyReport.pdf", reportBytes);
    
    emailManager.SendEmail(message);
}

Attaching Multiple Files:

using (var emailManager = new EmailManager())
{
    var message = EmailManager.CreateEmail(templateId, model);
    message.To.Add(new System.Net.Mail.MailAddress("recipient@example.com"));
    
    // Attach multiple files
    emailManager.AttachFile(message, "Report.pdf", reportBytes);
    emailManager.AttachFile(message, "Data.xlsx", excelBytes);
    emailManager.AttachFile(message, "Summary.docx", wordBytes);
    
    emailManager.SendEmail(message);
}
💡 Note: If the name parameter is not provided, the attachment will be named automatically (e.g., "attachment_1", "attachment_2").

CreateAttachment (string documentId)

Constructs an attachment from a Document, which can be added to the outbound MailMessage.

Parameters:

  • documentId (string) - The ID of the document to create an attachment from

Returns:

  • Attachment - An attachment object that can be added to a MailMessage

Description:

This method retrieves a document from the platform by its ID and creates an Attachment object that can be added to a MailMessage. The document type cannot be a YouTube/Vimeo Video or Link.

Unlike AttachFile, this method returns the Attachment object without adding it to a message, giving you more control over when and how to add it.

Usage Example:

var doc = Database.Query<Document>()
    .Where(a => a.Name == "Contract.pdf")
    .First();

using (var emailManager = new EmailManager())
{
    // Create the attachment but don't add it yet
    var attachment = emailManager.CreateAttachment(doc.Id);
    
    var message = new System.Net.Mail.MailMessage();
    message.From = new System.Net.Mail.MailAddress("sender@example.com");
    message.To.Add("recipient@example.com");
    message.Subject = "Contract Document";
    message.Body = "Attached is the contract for your review.";
    
    // Manually add the attachment
    message.Attachments.Add(attachment);
    
    emailManager.SendEmail(message);
}

Conditionally Adding Attachments:

using (var emailManager = new EmailManager())
{
    var message = EmailManager.CreateEmail(templateId, model);
    message.To.Add(new System.Net.Mail.MailAddress("recipient@example.com"));
    
    // Only attach document if certain condition is met
    if (includeContract)
    {
        var contractAttachment = emailManager.CreateAttachment(contractDocId);
        message.Attachments.Add(contractAttachment);
    }
    
    if (includeProposal)
    {
        var proposalAttachment = emailManager.CreateAttachment(proposalDocId);
        message.Attachments.Add(proposalAttachment);
    }
    
    emailManager.SendEmail(message);
}
⚠️ Warning: The document type cannot be a YouTube/Vimeo Video or Link. A ValidationException will be thrown for invalid document types.
💡 Note: The method returns null if the document bytes cannot be retrieved. Always check for null before adding to a message.

CreateAttachment (string name, byte[] fileBytes)

Constructs an attachment from an array of bytes, which can be added to the outbound MailMessage.

Parameters:

  • name (string) - The filename for the attachment
  • fileBytes (byte[]) - The file content as a byte array

Returns:

  • Attachment - An attachment object that can be added to a MailMessage

Description:

This method creates an Attachment object from a byte array with the specified filename. The attachment can then be manually added to one or more MailMessage objects.

This is useful when you need to reuse the same attachment across multiple messages or when you want more control over the attachment creation process.

Usage Example:

byte[] reportBytes = GenerateQuarterlyReport();

using (var emailManager = new EmailManager())
{
    // Create the attachment once
    var attachment = emailManager.CreateAttachment("Q4Report.pdf", reportBytes);
    
    var message = new System.Net.Mail.MailMessage();
    message.From = new System.Net.Mail.MailAddress("sender@example.com");
    message.To.Add("recipient@example.com");
    message.Subject = "Q4 Report";
    message.Body = "Please review the attached Q4 report.";
    
    message.Attachments.Add(attachment);
    
    emailManager.SendEmail(message);
}

Reusing Attachments for Multiple Recipients:

byte[] newsletterPdf = GenerateNewsletter();
var recipients = new[] { "user1@example.com", "user2@example.com", "user3@example.com" };

using (var emailManager = new EmailManager())
{
    foreach (var recipient in recipients)
    {
        // Create a fresh attachment for each message
        var attachment = emailManager.CreateAttachment("Newsletter.pdf", newsletterPdf);
        
        var message = new System.Net.Mail.MailMessage();
        message.From = new System.Net.Mail.MailAddress("sender@example.com");
        message.To.Add(recipient);
        message.Subject = "Monthly Newsletter";
        message.Body = "See attached newsletter.";
        message.Attachments.Add(attachment);
        
        emailManager.SendEmail(message);
    }
}
💡 Note: If the name parameter is null or empty, an automatic filename is generated with a timestamp.

CreateEmail (string templateId, object model, Dictionary<string,object> dataBag)

Static method. Constructs a single outbound email object from the specified template.

Parameters:

  • templateId (string) - The ID of the email template to use
  • model (object) - The primary data object for merge field population
  • dataBag (Dictionary<string,object>) - Optional. Additional data objects for merge fields

Returns:

  • MailMessage - A constructed email message ready to be customized and sent

Description:

This static method creates a MailMessage from an email template by its ID. The template's subject and body are processed with merge fields populated from the model object and optional dataBag.

The method retrieves the template from the database, processes merge fields using the Formula engine, and returns a fully constructed MailMessage. The caller is responsible for setting recipients (To, CC, BCC) and sending the message.

The dataBag parameter is optional and allows passing additional data objects that can be referenced in template merge fields beyond the primary model.

Usage Example:

var contact = Database.Query<Contact>()
    .Where(a => a.Name == "John Smith")
    .First();

using (var emailManager = new EmailManager())
{
    // Create an email message using an existing email template
    var message = EmailManager.CreateEmail("TemplateId_Here", contact);
    
    // Add recipient to the "To" list
    message.To.Add(new System.Net.Mail.MailAddress(contact.Email, contact.Name));
    
    // Send the email message
    emailManager.SendEmail(message);
}

Using DataBag for Additional Data:

var opportunity = Database.Query<Opportunity>()
    .Where(a => a.Id == opportunityId)
    .First();

var account = Database.Retrieve<Account>(opportunity.AccountId);

// Create data bag with additional objects
var dataBag = new Dictionary<string, object>
{
    { "Account", account },
    { "CompanyInfo", SystemInfo.Company }
};

using (var emailManager = new EmailManager())
{
    // Pass both model and dataBag
    var message = EmailManager.CreateEmail(
        "OpportunityUpdateTemplate", 
        opportunity, 
        dataBag
    );
    
    message.To.Add(new System.Net.Mail.MailAddress(opportunity.OwnerEmail));
    emailManager.SendEmail(message);
}

Customizing the Message Before Sending:

using (var emailManager = new EmailManager())
{
    var message = EmailManager.CreateEmail(templateId, contact);
    
    // Customize the message
    message.To.Add(new System.Net.Mail.MailAddress(contact.Email, contact.Name));
    message.CC.Add(new System.Net.Mail.MailAddress("manager@example.com"));
    message.Priority = System.Net.Mail.MailPriority.High;
    
    // Add attachments
    var attachment = emailManager.CreateAttachment(documentId);
    message.Attachments.Add(attachment);
    
    emailManager.SendEmail(message);
}
⚠️ Warning: A ValidationException is thrown if the template ID is invalid or the template cannot be found.
💡 Note: The returned MailMessage does not have recipients set. You must add at least one recipient to To, CC, or BCC before sending.

CreateEmail (EmailTemplate template, object model, Dictionary<string,object> dataBag)

Static method. Constructs a single outbound email object from the specified template.

Parameters:

  • template (EmailTemplate) - The email template object to use
  • model (object) - The primary data object for merge field population
  • dataBag (Dictionary<string,object>) - Optional. Additional data objects for merge fields

Returns:

  • MailMessage - A constructed email message ready to be customized and sent

Description:

This static method creates a MailMessage from an EmailTemplate object. Unlike the string templateId overload, this method accepts a pre-retrieved template object, which can be more efficient when you already have the template loaded.

The template's subject and body are processed with merge fields populated from the model and optional dataBag. The method handles Text, HTML, and Active Page template types automatically.

Usage Example:

var emailTemplate = Database.Query<EmailTemplate>()
    .Where(a => a.Name == "Welcome Email")
    .First();

var user = SystemInfo.UserInfo;

using (var emailManager = new EmailManager())
{
    // Create email from template object
    var message = EmailManager.CreateEmail(emailTemplate, user);
    
    message.To.Add(new System.Net.Mail.MailAddress(user.Email, user.Name));
    emailManager.SendEmail(message);
}

Reusing Template for Multiple Recipients:

var emailTemplate = Database.Query<EmailTemplate>()
    .Where(a => a.Name == "Monthly Update")
    .First();

var subscribers = Database.Query<Contact>()
    .Where(c => c.IsSubscribed == true)
    .ToList();

using (var emailManager = new EmailManager())
{
    foreach (var subscriber in subscribers)
    {
        // Create message for each subscriber
        var message = EmailManager.CreateEmail(emailTemplate, subscriber);
        message.To.Add(new System.Net.Mail.MailAddress(subscriber.Email, subscriber.Name));
        
        emailManager.SendEmail(message);
    }
}

Using with Active Page Templates:

var emailTemplate = Database.Query<EmailTemplate>()
    .Where(a => a.Name == "Rich HTML Template")
    .First();

var invoice = Database.Retrieve<Invoice>(invoiceId);

var dataBag = new Dictionary<string, object>
{
    { "LineItems", invoice.LineItems },
    { "Customer", invoice.Customer }
};

using (var emailManager = new EmailManager())
{
    var message = EmailManager.CreateEmail(emailTemplate, invoice, dataBag);
    message.To.Add(new System.Net.Mail.MailAddress(invoice.CustomerEmail));
    
    emailManager.SendEmail(message);
}
⚠️ Warning: A ValidationException is thrown if the template is null or if an Active Page template has no associated Active Page.
💡 Note: For Active Page templates, the full HTML is rendered using the Active Page engine before being set as the message body.

SendEmail (MailMessage message)

Sends an outbound email using the MailMessage.

Parameters:

  • message (MailMessage) - The email message to send

Returns:

  • void

Description:

This method sends a single email message using the configured SMTP settings. The message must have at least one recipient in the To, CC, or BCC fields.

If the message's From address is not set or is empty, the method automatically sets it using the company's communication email or default from address. The email is sent synchronously using the SMTP client.

Usage Example:

var contact = Database.Query<Contact>()
    .Where(a => a.Name == "John Smith")
    .First();

using (var emailManager = new EmailManager())
{
    // Create an email message using an existing email template
    var message = EmailManager.CreateEmail("WelcomeTemplate", contact);
    
    // Add recipient
    message.To.Add(new System.Net.Mail.MailAddress(contact.Email, contact.Name));
    
    // Send the email message
    emailManager.SendEmail(message);
}

Sending with Multiple Recipients:

using (var emailManager = new EmailManager())
{
    var message = EmailManager.CreateEmail(templateId, model);
    
    // Add multiple recipients
    message.To.Add(new System.Net.Mail.MailAddress("user1@example.com", "User One"));
    message.To.Add(new System.Net.Mail.MailAddress("user2@example.com", "User Two"));
    message.CC.Add(new System.Net.Mail.MailAddress("manager@example.com"));
    
    emailManager.SendEmail(message);
}

Sending with Attachments:

using (var emailManager = new EmailManager())
{
    var message = EmailManager.CreateEmail(templateId, model);
    message.To.Add(new System.Net.Mail.MailAddress("recipient@example.com"));
    
    // Add attachment
    var attachment = emailManager.CreateAttachment(documentId);
    message.Attachments.Add(attachment);
    
    emailManager.SendEmail(message);
}
💡 Note: The message and its attachments are automatically disposed after sending. You do not need to manually dispose of the MailMessage when using this method.

SendEmail (string to, string subject, string message)

Sends an outbound email to the email address provided.

Parameters:

  • to (string) - The recipient email address
  • subject (string) - The email subject line
  • message (string) - The email body content

Returns:

  • void

Description:

This convenience method sends a simple text email to a single recipient without requiring template creation or MailMessage construction. The From address is automatically set using company preferences.

This is the simplest way to send a basic notification or alert email when templates are not needed.

Usage Example:

using (var emailManager = new EmailManager())
{
    emailManager.SendEmail(
        "user@example.com",
        "Account Activated",
        "Your account has been successfully activated. You can now log in."
    );
}

Sending Simple Notifications:

public void NotifyUserOfUpdate(string userEmail, string itemName)
{
    using (var emailManager = new EmailManager())
    {
        string subject = $"Update: {itemName}";
        string body = $"The item '{itemName}' has been updated. Please review the changes.";
        
        emailManager.SendEmail(userEmail, subject, body);
    }
}

Sending Alert Emails:

public void SendErrorAlert(string adminEmail, string errorDetails)
{
    using (var emailManager = new EmailManager())
    {
        emailManager.SendEmail(
            adminEmail,
            "System Alert: Error Detected",
            $"An error has occurred:\n\n{errorDetails}"
        );
    }
}
💡 Note: This method sends plain text emails only. For HTML emails or template-based messages, use the CreateEmail method instead.

SendEmails (List<MailMessage> messages)

Sends one or more outbound emails using the list of MailMessages.

Parameters:

  • messages (List<MailMessage>) - A list of email messages to send

Returns:

  • void

Description:

This method sends multiple email messages efficiently in a batch operation. All messages are processed and sent through the shared services infrastructure, which provides better performance than sending messages individually.

For each message, if the From address is not set, it is automatically populated using company preferences. The method handles SMTP configuration automatically, using company-specific SMTP settings when available or falling back to web.config defaults.

All messages and their attachments are automatically disposed after sending.

Usage Example:

var contacts = Database.Query<Contact>()
    .Where(c => c.IsActive == true)
    .Take(100)
    .ToList();

var messages = new List<System.Net.Mail.MailMessage>();

foreach (var contact in contacts)
{
    var message = EmailManager.CreateEmail("NewsletterTemplate", contact);
    message.To.Add(new System.Net.Mail.MailAddress(contact.Email, contact.Name));
    messages.Add(message);
}

using (var emailManager = new EmailManager())
{
    // Send all messages in batch
    emailManager.SendEmails(messages);
}

Sending Personalized Batch Emails:

public void SendQuarterlyReports()
{
    var managers = Database.Query<User>()
        .Where(u => u.Role == "Manager")
        .ToList();
    
    var messages = new List<System.Net.Mail.MailMessage>();
    
    foreach (var manager in managers)
    {
        // Get manager's data
        var report = GenerateQuarterlyReport(manager.Id);
        
        // Create personalized message
        var message = EmailManager.CreateEmail("QuarterlyReportTemplate", report);
        message.To.Add(new System.Net.Mail.MailAddress(manager.Email, manager.Name));
        
        messages.Add(message);
    }
    
    using (var emailManager = new EmailManager())
    {
        emailManager.SendEmails(messages);
    }
}

Sending with Conditional Attachments:

var opportunities = Database.Query<Opportunity>()
    .Where(o => o.Stage == "Closed Won")
    .ToList();

var messages = new List<System.Net.Mail.MailMessage>();

using (var emailManager = new EmailManager())
{
    foreach (var opp in opportunities)
    {
        var message = EmailManager.CreateEmail("ClosedWonTemplate", opp);
        message.To.Add(new System.Net.Mail.MailAddress(opp.OwnerEmail));
        
        // Conditionally add contract attachment
        if (!string.IsNullOrEmpty(opp.ContractDocumentId))
        {
            var attachment = emailManager.CreateAttachment(opp.ContractDocumentId);
            message.Attachments.Add(attachment);
        }
        
        messages.Add(message);
    }
    
    emailManager.SendEmails(messages);
}
💡 Note: This method is more efficient than calling SendEmail multiple times in a loop. Use this for bulk email operations.
⚠️ Warning: If the messages list is null, an ArgumentNullException is thrown. If the list is empty, the method returns without performing any operations.

Error Handling

Common Exceptions

ExceptionCauseResolution
ArgumentNullExceptionRequired parameter (message, stream, content, etc.) is nullEnsure all required parameters are provided and not null
ValidationExceptionInvalid template ID, missing document, invalid document type, or missing handlerVerify template exists, document IDs reference valid documents of supported types
ExceptionStream cannot be read from attachmentEnsure attachment streams are readable and seekable when possible
SmtpExceptionSMTP server connection or authentication failureVerify SMTP settings in Company Preferences or web.config

Validation Errors

💡 Note: The following validations are automatically performed:
  • Email templates must exist when referenced by ID
  • Document IDs must reference valid documents
  • Documents used as attachments cannot be YouTube/Vimeo videos or links
  • Attachment streams must be readable
  • At least one recipient (To, CC, or BCC) must be specified

SMTP Configuration Issues

If emails fail to send, verify:

  1. Company Preferences contain valid SMTP settings (server, port, credentials)
  2. Web.config contains fallback SMTP configuration
  3. SMTP server is accessible from the application server
  4. Firewall rules allow outbound SMTP traffic
  5. SMTP credentials are correct and the account has send permissions

Best Practices

Always Use using Statements

EmailManager implements IDisposable and manages SMTP client resources. Always dispose properly:

using (var emailManager = new EmailManager())
{
    // Email operations
} // Automatically disposes resources

Validate Templates Before Use

When working with template IDs, verify the template exists:

var template = Database.Query<EmailTemplate>()
    .Where(a => a.Id == templateId)
    .FirstOrDefault();

if (template == null)
{
    SystemInfo.Debug("Template not found: " + templateId);
    return;
}

Handle Attachments Carefully

When adding multiple attachments, ensure all resources are properly managed:

using (var emailManager = new EmailManager())
{
    var message = new System.Net.Mail.MailMessage();
    
    try
    {
        // Add attachments
        var attachment1 = emailManager.CreateAttachment("File1.pdf", bytes1);
        var attachment2 = emailManager.CreateAttachment("File2.pdf", bytes2);
        
        message.Attachments.Add(attachment1);
        message.Attachments.Add(attachment2);
        
        // Send email
        emailManager.SendEmail(message);
    }
    finally
    {
        // Attachments are automatically disposed when message is sent
    }
}

Use Data Bags for Complex Templates

When templates require multiple data sources, use the optional data bag parameter:

var model = new { CustomerName = "John Doe", OrderId = "12345" };
var dataBag = new Dictionary<string, object>
{
    { "CompanyInfo", companyDetails },
    { "OrderDetails", orderData }
};

var message = EmailManager.CreateEmail(templateId, model, dataBag);

Batch Email Operations

For multiple emails, use SendEmails for better performance:

var messages = new List<System.Net.Mail.MailMessage>();

foreach (var recipient in recipients)
{
    var message = EmailManager.CreateEmail(templateId, recipient);
    message.To.Add(new System.Net.Mail.MailAddress(recipient.Email, recipient.Name));
    messages.Add(message);
}

using (var emailManager = new EmailManager())
{
    emailManager.SendEmails(messages);
}

Set Email Priority When Needed

For urgent notifications, set the message priority:

var message = EmailManager.CreateEmail(templateId, model);
message.To.Add(new System.Net.Mail.MailAddress(recipient));
message.Priority = System.Net.Mail.MailPriority.High;