Skip to content

Repository files navigation

Email Notification on Status Change

A configurable, metadata-driven Salesforce solution for sending email notifications when record status fields change to specific values. Zero code changes required to add new notifications — just create configuration records.

Features

  • Fully Declarative Configuration — Add new email notifications without writing code
  • Works with Any Object — Standard or custom objects
  • Flexible Recipient Options — Send to Contact, User, Lead lookups, or direct email fields
  • CC Support — Add multiple CC recipients per configuration
  • Org-Wide Email Address Support — Send from verified org-wide email addresses
  • Template Merge Fields — Full support for Salesforce email template merge fields
  • Bulk-Safe — Handles large data volumes with proper caching
  • Insert & Update Support — Trigger emails on record creation or status changes

Components

Component Type Description
Email_Notification_Config__c Custom Object Stores email notification configurations
EmailNotificationUtility Apex Class Core utility that processes and sends emails
EmailNotificationUtilityTest Test Class 100% coverage test class

Installation

Option 1: Deploy via Salesforce CLI

# Authenticate to your org
sf org login web -a YourOrgAlias

# Deploy the package
sf project deploy start -d force-app -o YourOrgAlias

Option 2: Deploy via VS Code

  1. Open the project in VS Code with Salesforce Extensions
  2. Right-click on force-app folder
  3. Select SFDX: Deploy Source to Org

Configuration

Step 1: Create an Email Template

Create a Salesforce Email Template (Classic or Lightning) for your notification. Note the Developer Name (not the Label).

Step 2: Create a Configuration Record

Navigate to the Email Notification Configs tab and create a new record:

Field Description Example
Object API Name API name of the object to monitor Proposal__c, Case, Opportunity
Status Field API Name API name of the field to watch for changes Status__c, StageName, Status
Status Value The value that triggers the email Approved, Closed Won, Escalated
Email Template Developer Name Developer name of the email template Proposal_Approved_Notification
Recipient Field API Name Field containing the recipient (lookup or email) Contact__c, OwnerId, Email__c
Active Enable/disable this configuration ✓ (checked)
CC Email Addresses Comma-separated CC addresses (optional) manager@company.com, team@company.com
Org Wide Email Address Display Name of org-wide email address (optional) Support Team
Description Notes about this configuration (optional) Notify contact when proposal is approved

Recipient Field Options

The Recipient_Field_API_Name__c field supports multiple formats:

Type Example Description
Contact Lookup Contact__c Sends to the related Contact's email
User Lookup OwnerId Sends to the User's email
Lead Lookup Lead__c Sends to the related Lead's email
Email Field Email__c Sends directly to the email address in this field
Related Field Contact__r.Email Dot notation for related record fields

Usage

Add to Your Trigger

Create or update a trigger on the object you want to monitor:

trigger ProposalTrigger on Proposal__c (after insert, after update) {
    
    if (Trigger.isAfter) {
        if (Trigger.isInsert) {
            // Check for matching status on insert
            EmailNotificationUtility.processStatusChangeEmailsOnInsert(
                'Proposal__c', 
                Trigger.new
            );
        }
        
        if (Trigger.isUpdate) {
            // Check for status changes on update
            EmailNotificationUtility.processStatusChangeEmails(
                'Proposal__c', 
                Trigger.oldMap, 
                Trigger.newMap
            );
        }
    }
}

Using with a Trigger Framework

If you use a trigger handler framework:

public class ProposalTriggerHandler extends TriggerHandler {
    
    public override void afterInsert() {
        EmailNotificationUtility.processStatusChangeEmailsOnInsert(
            'Proposal__c', 
            Trigger.new
        );
    }
    
    public override void afterUpdate() {
        EmailNotificationUtility.processStatusChangeEmails(
            'Proposal__c', 
            Trigger.oldMap, 
            Trigger.newMap
        );
    }
}

Examples

Example 1: Notify Contact When Proposal is Approved

Configuration:

  • Object API Name: Proposal__c
  • Status Field API Name: Status__c
  • Status Value: Approved
  • Email Template Developer Name: Proposal_Approved
  • Recipient Field API Name: Contact__c
  • Active: ✓

Example 2: Notify Case Owner When Case is Escalated

Configuration:

  • Object API Name: Case
  • Status Field API Name: Priority
  • Status Value: High
  • Email Template Developer Name: Case_Escalation_Alert
  • Recipient Field API Name: OwnerId
  • CC Email Addresses: support-manager@company.com
  • Org Wide Email Address: Support Team
  • Active: ✓

Example 3: Notify Multiple Stakeholders on Opportunity Close

Configuration:

  • Object API Name: Opportunity
  • Status Field API Name: StageName
  • Status Value: Closed Won
  • Email Template Developer Name: Opp_Won_Notification
  • Recipient Field API Name: Contact__r.Email
  • CC Email Addresses: sales-ops@company.com, finance@company.com
  • Active: ✓

API Reference

EmailNotificationUtility Methods

processStatusChangeEmails

public static void processStatusChangeEmails(
    String objectApiName, 
    Map<Id, SObject> oldMap, 
    Map<Id, SObject> newMap
)

Use in after update trigger context. Sends emails when a status field changes TO the configured target value.

processStatusChangeEmailsOnInsert

public static void processStatusChangeEmailsOnInsert(
    String objectApiName, 
    List<SObject> newRecords
)

Use in after insert trigger context. Sends emails when a new record is created with the target status value.

processStatusChangeEmailsWithRenderedContent

public static void processStatusChangeEmailsWithRenderedContent(
    String objectApiName, 
    Map<Id, SObject> oldMap, 
    Map<Id, SObject> newMap
)

Alternative method that renders template content manually. Use this when you need CC addresses to work reliably with all recipient types.

Best Practices

  1. Use Descriptive Template Names — Makes configurations easier to manage
  2. Test in Sandbox First — Validate email content and recipients before production
  3. Monitor Email Limits — Salesforce has daily email limits; monitor usage for high-volume objects
  4. Use Org-Wide Addresses — Improves deliverability and provides consistent sender identity
  5. Keep Configurations Active/Inactive — Use the Active checkbox instead of deleting configs

Troubleshooting

Issue Solution
Emails not sending Check that the configuration is Active
Template merge fields empty Ensure the template's Related Entity Type matches your object
CC addresses not receiving Verify email addresses are valid; check spam folders
Org-Wide Email not working Verify the Display Name matches exactly (case-sensitive)
No email on insert Make sure you're calling processStatusChangeEmailsOnInsert

License

MIT License — free to use and modify.

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Submit a pull request

Questions or issues? Open an issue on GitHub.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages