Custom Email Notifications
The EmailNotifications property on the ParticipantInsertModel enables you to programmatically define custom email notifications that override the standard EmailTemplateSetName configuration. This powerful feature gives you complete control over notification timing, content, and personalization, allowing you to implement scenarios like reminder emails, multi-stage communications, and highly customized messaging without creating multiple notification templates in the Control Panel.
When to Use EmailNotifications
The EmailNotifications property is ideal when you need:
- Custom Subject and Body: Fully customized email content that goes beyond what your notification templates provide
- Dynamic Placeholders: Runtime-generated placeholder values that change per transaction or participant
- Delayed Notifications: Reminder emails sent hours or days after the initial notification
- Multiple Notifications: Sequential emails (e.g., initial request, 24-hour reminder, 72-hour final notice)
- Template Enhancement: Use your existing
EmailTemplateSetNametemplates but inject custom placeholder values
Note: If you only need static placeholder values (like company phone numbers or support links), use the EmailTemplatePlaceholders property instead. Use EmailNotifications when you need custom subjects, bodies, or delayed delivery.
Property Schema
The EmailNotifications property is an array of notification objects, each with the following properties:
| Property | Type | Required | Description |
|---|---|---|---|
Subject | string (nullable) | No | Custom email subject line. If null, uses the subject from EmailTemplateSetName. |
BodyHtml | string (nullable) | No | Custom HTML email body. If null, uses the body from EmailTemplateSetName. |
Placeholders | array | No | Array of placeholder name/value pairs for dynamic content replacement in both subject and body. |
SendDelayInMinutes | integer | No | Minutes to wait before sending, calculated from when participant notifications first become eligible to send (not from transaction creation time). Default is 0. |
Placeholder Object Structure
Each placeholder in the Placeholders array contains:
| Property | Type | Required | Description |
|---|---|---|---|
Name | string | Yes | Placeholder name (without curly braces). Referenced in templates as {{Name}}. |
Value | string | Yes | The value to replace the placeholder with in the email. |
Code Examples
Basic Custom Notification
This example sends a fully customized email with a custom subject and HTML body:
var req = new TransactionCreateRequestModel()
{
Transactions = new List<object>
{
new TransactionCreateModel()
{
Description = "Loan Agreement - Custom Notification",
Participants = new List<object>
{
new ParticipantInsertModel()
{
FullName = "Sarah Johnson",
EmailAddress = "sarah.johnson@example.com",
SendRequestViaEmail = true,
EmailNotifications = new List<object>
{
new EmailNotificationModel()
{
Subject = "Action Required: Your Loan Agreement Needs Signature",
BodyHtml = @"
<html>
<body style='font-family: Arial, sans-serif;'>
<h2>Hello {{PARTICIPANT_FIRSTNAME}},</h2>
<p>Your loan agreement is ready for signature. Please review and sign the document by clicking the link below:</p>
<p><a href='{{PARTICIPANT_ACCESSLINK}}' style='background-color: #0066cc; color: white; padding: 10px 20px; text-decoration: none; border-radius: 5px;'>Sign Document</a></p>
<p>If you have questions, contact our support team at support@example.com</p>
<p>Best regards,<br/>The Loan Processing Team</p>
</body>
</html>",
SendDelayInMinutes = 0
}
}
}
},
Documents = new List<object>
{
new DocumentInsertModel()
{
Title = "Loan Agreement",
Source = new SourceModel()
{
FileBytes = System.IO.File.ReadAllBytes(@"C:\Documents\LoanAgreement.pdf")
},
Tasks = new List<object>
{
new TaskInsertModel()
{
Type = TaskTypes.Signature
}
}
}
}
}
}
};
var api = new TransactionsApi(myRestEndpointUrl);
var results = api.CreateTransactions(req, apiKey, apiSecret, apiUsername, apiPassword);
const transactionRequest = {
Transactions: [
{
Description: 'Loan Agreement - Custom Notification',
Participants: [
{
FullName: 'Sarah Johnson',
EmailAddress: 'sarah.johnson@example.com',
SendRequestViaEmail: true,
EmailNotifications: [
{
Subject: 'Action Required: Your Loan Agreement Needs Signature',
BodyHtml: `
<html>
<body style='font-family: Arial, sans-serif;'>
<h2>Hello {{PARTICIPANT_FIRSTNAME}},</h2>
<p>Your loan agreement is ready for signature. Please review and sign the document by clicking the link below:</p>
<p><a href='{{PARTICIPANT_ACCESSLINK}}' style='background-color: #0066cc; color: white; padding: 10px 20px; text-decoration: none; border-radius: 5px;'>Sign Document</a></p>
<p>If you have questions, contact our support team at support@example.com</p>
<p>Best regards,<br/>The Loan Processing Team</p>
</body>
</html>`,
SendDelayInMinutes: 0,
},
],
},
],
Documents: [
{
Title: 'Loan Agreement',
Source: {
FileBytes: fileByteArray,
},
Tasks: [
{
Type: 'Signature',
},
],
},
],
},
],
}
// Using axios or similar HTTP client
const response = await axios.post('/api/transactions/create', transactionRequest, {
headers: {
'ApiKey': apiKey,
'ApiSecret': apiSecret,
},
})
Using Templates with Custom Placeholders
You can leverage your existing EmailTemplateSetName templates while injecting custom placeholder values by setting both Subject and BodyHtml to null:
var req = new TransactionCreateRequestModel()
{
Transactions = new List<object>
{
new TransactionCreateModel()
{
Description = "Policy Renewal with Custom Data",
Participants = new List<object>
{
new ParticipantInsertModel()
{
FullName = "Michael Chen",
EmailAddress = "michael.chen@example.com",
SendRequestViaEmail = true,
EmailTemplateSetName = "PolicyRenewalTemplates",
EmailNotifications = new List<object>
{
new EmailNotificationModel()
{
Subject = null, // Uses template subject
BodyHtml = null, // Uses template body
SendDelayInMinutes = 0,
Placeholders = new List<object>
{
new EmailNotificationPlaceholderModel()
{
Name = "PolicyNumber",
Value = "POL-2025-12345"
},
new EmailNotificationPlaceholderModel()
{
Name = "ExpirationDate",
Value = "December 31, 2025"
},
new EmailNotificationPlaceholderModel()
{
Name = "AgentName",
Value = "Jennifer Williams"
},
new EmailNotificationPlaceholderModel()
{
Name = "AgentPhone",
Value = "(555) 123-4567"
}
}
}
}
}
},
Documents = new List<object>
{
new DocumentInsertModel()
{
Title = "Policy Renewal Documents",
Source = new SourceModel()
{
FileBytes = System.IO.File.ReadAllBytes(@"C:\Policies\Renewal.pdf")
},
Tasks = new List<object>
{
new TaskInsertModel()
{
Type = TaskTypes.Signature
}
}
}
}
}
}
};
const transactionRequest = {
Transactions: [
{
Description: 'Policy Renewal with Custom Data',
Participants: [
{
FullName: 'Michael Chen',
EmailAddress: 'michael.chen@example.com',
SendRequestViaEmail: true,
EmailTemplateSetName: 'PolicyRenewalTemplates',
EmailNotifications: [
{
Subject: null, // Uses template subject
BodyHtml: null, // Uses template body
SendDelayInMinutes: 0,
Placeholders: [
{
Name: 'PolicyNumber',
Value: 'POL-2025-12345',
},
{
Name: 'ExpirationDate',
Value: 'December 31, 2025',
},
{
Name: 'AgentName',
Value: 'Jennifer Williams',
},
{
Name: 'AgentPhone',
Value: '(555) 123-4567',
},
],
},
],
},
],
Documents: [
{
Title: 'Policy Renewal Documents',
Source: {
FileBytes: fileByteArray,
},
Tasks: [
{
Type: 'Signature',
},
],
},
],
},
],
}
Your PolicyRenewalTemplates notification template might contain placeholders like:
<p>Policy Number: {{PolicyNumber}}</p>
<p>Current Policy Expires: {{ExpirationDate}}</p>
<p>Your Agent: {{AgentName}} - {{AgentPhone}}</p>
Multiple Delayed Notifications (Reminder Sequence)
Send a series of reminder emails at different intervals without creating multiple notification templates:
new ParticipantInsertModel()
{
FullName = "David Martinez",
EmailAddress = "david.martinez@example.com",
SendRequestViaEmail = true,
EmailTemplateSetName = "StandardNotifications",
EmailNotifications = new List<object>
{
// Initial notification (sent immediately)
new EmailNotificationModel()
{
Subject = "Action Required: Sign Your Employment Agreement",
BodyHtml = @"
<html>
<body>
<p>Hello {{PARTICIPANT_FIRSTNAME}},</p>
<p>Please review and sign your employment agreement:</p>
<p><a href='{{PARTICIPANT_ACCESSLINK}}'>Sign Now</a></p>
<p>Thank you,<br/>HR Team</p>
</body>
</html>",
SendDelayInMinutes = 0
},
// First reminder (24 hours later)
new EmailNotificationModel()
{
Subject = "Reminder: Employment Agreement Signature Needed",
BodyHtml = @"
<html>
<body>
<p>Hi {{PARTICIPANT_FIRSTNAME}},</p>
<p>This is a friendly reminder that your employment agreement is still waiting for your signature.</p>
<p><a href='{{PARTICIPANT_ACCESSLINK}}'>Complete Signing</a></p>
<p>Best regards,<br/>HR Team</p>
</body>
</html>",
SendDelayInMinutes = 1440 // 24 hours
},
// Second reminder (72 hours later)
new EmailNotificationModel()
{
Subject = "Final Reminder: Employment Agreement Requires Your Attention",
BodyHtml = @"
<html>
<body>
<p>Dear {{PARTICIPANT_FIRSTNAME}},</p>
<p><strong>This is your final reminder.</strong> Your employment agreement must be signed to complete your onboarding process.</p>
<p><a href='{{PARTICIPANT_ACCESSLINK}}'>Sign Document Now</a></p>
<p>If you have any questions or issues, please contact us at hr@example.com</p>
<p>HR Department</p>
</body>
</html>",
SendDelayInMinutes = 4320 // 72 hours
}
}
}
{
"FullName": "David Martinez",
"EmailAddress": "david.martinez@example.com",
"SendRequestViaEmail": true,
"EmailTemplateSetName": "StandardNotifications",
"EmailNotifications": [
// Initial notification (sent immediately)
{
"Subject": "Action Required: Sign Your Employment Agreement",
"BodyHtml": `
<html>
<body>
<p>Hello {{PARTICIPANT_FIRSTNAME}},</p>
<p>Please review and sign your employment agreement:</p>
<p><a href='{{PARTICIPANT_ACCESSLINK}}'>Sign Now</a></p>
<p>Thank you,<br/>HR Team</p>
</body>
</html>`,
"SendDelayInMinutes": 0
},
// First reminder (24 hours later)
{
"Subject": "Reminder: Employment Agreement Signature Needed",
"BodyHtml": `
<html>
<body>
<p>Hi {{PARTICIPANT_FIRSTNAME}},</p>
<p>This is a friendly reminder that your employment agreement is still waiting for your signature.</p>
<p><a href='{{PARTICIPANT_ACCESSLINK}}'>Complete Signing</a></p>
<p>Best regards,<br/>HR Team</p>
</body>
</html>`,
"SendDelayInMinutes": 1440 // 24 hours
},
// Second reminder (72 hours later)
{
"Subject": "Final Reminder: Employment Agreement Requires Your Attention",
"BodyHtml": `
<html>
<body>
<p>Dear {{PARTICIPANT_FIRSTNAME}},</p>
<p><strong>This is your final reminder.</strong> Your employment agreement must be signed to complete your onboarding process.</p>
<p><a href='{{PARTICIPANT_ACCESSLINK}}'>Sign Document Now</a></p>
<p>If you have any questions or issues, please contact us at hr@example.com</p>
<p>HR Department</p>
</body>
</html>`,
"SendDelayInMinutes": 4320 // 72 hours
}
]
}
Timing Note: The SendDelayInMinutes is calculated from when participant notifications first become eligible to send, not from transaction creation time. If a participant has dependencies or prerequisites, delayed notifications start counting after those conditions are met.
Placeholder Integration
System Placeholders
All system-provided placeholders are available for use in both custom Subject and BodyHtml content. The most commonly used placeholders for participant notifications include:
{{PARTICIPANT_ACCESSLINK}}- Direct link to the participant's signing workflow{{PARTICIPANT_ACCESSTINYLINK}}- Shortened version of the access link{{PARTICIPANT_FULLNAME}}- Full name of the participant{{PARTICIPANT_FIRSTNAME}}- First name only{{PARTICIPANT_EMAILADDRESS}}- Email address{{TRANSACTION_DESCRIPTION}}- Description of the transaction{{DOCUMENT_TITLE}}- Title of the document(s){{LAUNCHER_FULLNAME}}- Name of the person who created the transaction
See the complete Notification Placeholders reference for all available system placeholders.
Custom Placeholders
In addition to system placeholders, you can define your own custom placeholders in the Placeholders array. These are particularly useful for:
- Business-specific data (policy numbers, account IDs, reference codes)
- Dynamic dates and deadlines
- Agent or representative contact information
- Conditional messaging based on transaction metadata
EmailNotifications = new List<object>
{
new EmailNotificationModel()
{
Subject = "Contract {{ContractNumber}} - {{ContractType}}",
BodyHtml = @"
<p>Dear {{PARTICIPANT_FIRSTNAME}},</p>
<p>Your {{ContractType}} (Contract #{{ContractNumber}}) is ready for signature.</p>
<p>Deadline: {{SigningDeadline}}</p>
<p><a href='{{PARTICIPANT_ACCESSLINK}}'>Review and Sign</a></p>
<p>Questions? Contact {{AssignedAgent}} at {{AgentEmail}}</p>",
Placeholders = new List<object>
{
new EmailNotificationPlaceholderModel()
{
Name = "ContractNumber",
Value = "CTR-2025-7891"
},
new EmailNotificationPlaceholderModel()
{
Name = "ContractType",
Value = "Annual Service Agreement"
},
new EmailNotificationPlaceholderModel()
{
Name = "SigningDeadline",
Value = "December 15, 2025"
},
new EmailNotificationPlaceholderModel()
{
Name = "AssignedAgent",
Value = "Rebecca Thompson"
},
new EmailNotificationPlaceholderModel()
{
Name = "AgentEmail",
Value = "rebecca.thompson@example.com"
}
}
}
}
EmailNotifications: [
{
Subject: 'Contract {{ContractNumber}} - {{ContractType}}',
BodyHtml: `
<p>Dear {{PARTICIPANT_FIRSTNAME}},</p>
<p>Your {{ContractType}} (Contract #{{ContractNumber}}) is ready for signature.</p>
<p>Deadline: {{SigningDeadline}}</p>
<p><a href='{{PARTICIPANT_ACCESSLINK}}'>Review and Sign</a></p>
<p>Questions? Contact {{AssignedAgent}} at {{AgentEmail}}</p>`,
Placeholders: [
{
Name: 'ContractNumber',
Value: 'CTR-2025-7891',
},
{
Name: 'ContractType',
Value: 'Annual Service Agreement',
},
{
Name: 'SigningDeadline',
Value: 'December 15, 2025',
},
{
Name: 'AssignedAgent',
Value: 'Rebecca Thompson',
},
{
Name: 'AgentEmail',
Value: 'rebecca.thompson@example.com',
},
],
},
]
Placeholder Precedence
When both EmailNotifications and EmailTemplatePlaceholders are defined for a participant:
EmailNotificationsplaceholders take precedence for the participant request emailEmailTemplatePlaceholdersapplies to all other notification types (completion, cancellation, etc.)
This allows you to use global placeholders across all transaction emails while overriding specific values for the initial participant notification.
Delayed Notifications
The SendDelayInMinutes property enables powerful reminder and follow-up scenarios without manual intervention or external scheduling systems.
Common Use Cases
Signature Reminders
- Initial request:
SendDelayInMinutes = 0 - First reminder:
SendDelayInMinutes = 1440(24 hours) - Final reminder:
SendDelayInMinutes = 4320(72 hours)
Compliance Deadlines
- Notification 7 days before deadline:
SendDelayInMinutes = 10080 - Final warning 24 hours before deadline:
SendDelayInMinutes = 11520
Progressive Urgency
- Standard request initially
- Polite reminder after 2 days
- Urgent escalation after 5 days with different contact information
Timing Mechanics
The delay timer starts when the participant's notifications first become eligible to send, which occurs when:
- All task prerequisites are met (e.g., previous signers have completed their tasks if sequential workflow)
- Any workflow dependencies are satisfied
- The participant's
SendRequestViaEmailistrue
Example: In a sequential signing workflow where Participant B signs after Participant A, if Participant B has a delayed notification with SendDelayInMinutes = 1440, the 24-hour countdown begins when Participant A completes their signature, not when the transaction is created.
Best Practices
HTML Email Design
When creating custom BodyHtml content:
- Use inline CSS - Many email clients strip
<style>tags and external stylesheets - Keep layouts simple - Complex CSS like flexbox or grid is not universally supported
- Test across clients - Gmail, Outlook, Apple Mail, and mobile clients render differently
- Include plain text fallback - Consider accessibility for text-only email clients
- Use absolute URLs - For images and links, always use full URLs (e.g.,
https://...)
<!-- Good: Inline CSS, simple table-based layout -->
<table style="width: 100%; max-width: 600px; font-family: Arial, sans-serif;">
<tr>
<td style="padding: 20px; background-color: #f5f5f5;">
<h2 style="color: #333; margin: 0 0 15px 0;">Action Required</h2>
<p style="color: #666; line-height: 1.6;">Your signature is needed...</p>
</td>
</tr>
</table>
Performance and Scalability
- Limit notification count - While you can define many notifications, consider that each adds processing overhead
- Reasonable delays - Very short delays (< 5 minutes) may batch together; use longer intervals for distinct reminders
- Monitor delivery - Use transaction logging to track which notifications were sent and when
Security Considerations
- Sanitize dynamic content - If placeholder values come from user input, ensure they are properly escaped
- Avoid sensitive data - Don't include passwords, full SSNs, or other sensitive information in email bodies
- Use HTTPS links - Always use
{{PARTICIPANT_ACCESSLINK}}which provides secure HTTPS URLs
Content Strategy
- Progressive urgency - Start friendly, increase urgency in later reminders without being confrontational
- Clear calls-to-action - Make the signing link prominent and clearly labeled
- Contact information - Always provide a way for recipients to ask questions or report issues
- Consistent branding - Match your organization's tone, terminology, and visual identity
Related Documentation
- Notification Placeholders - Complete reference of all available placeholders
- Notifications Customization - Creating and managing notification templates in the Control Panel
- Managing Participants - General participant management operations
- Renotifying a Participant - Manually triggering additional notifications