Admins / Developers / Sales

How to Use Custom Staging to Handle Email Volume Limits in Salesforce

By John Glennan & Sanjay Gorantla

Email is one of the most common and business-critical features in Salesforce. Whether it’s a lead notification, an onboarding welcome message, or an application status update, email helps teams communicate with customers and partners at scale. 

However, as many teams quickly discover, Salesforce has a hard limit: you can’t send more than 5,000 emails per day per org using its native messaging, the sendEmail() function. That cap includes scheduled emails, flow-generated alerts, and Apex-triggered messages, which isn’t just a technical limitation. 

It’s a serious operational risk for large organisations, especially in industries like healthcare, insurance, and animation. Missed messages can impact broker relationships, delay application processing, or even trigger compliance concerns.

We encountered this challenge in our Salesforce organisation while managing a high-volume broker’s communication flow. This is described through the solution we built: a metadata-driven, scalable email staging system and how it helped us overcome the 5K email cap, improve reliability, and empower business teams without sacrificing control.

When We Hit the 5K Email Wall

Initially, our Salesforce organization handled emails without issues. Whether it was a welcome message to a new broker, an application approval notification, or a reminder about missing documents, these emails were triggered automatically from Flows and Apex logic using Messaging.sendEmail()

However, as more teams, particularly our broker engagement and application processing teams, began to rely on Salesforce for outbound communications, we noticed something odd: emails weren’t arriving.

After digging in, we realized we had hit Salesforce’s hard limit of 5,000 outbound emails per day.

Once we reached the cap, emails silently stopped sending; there was no soft warning or configurable threshold. There was no retry mechanism, no notification to the sender, and no visibility into what failed.

This meant that:

  • Critical onboarding messages to brokers never arrived.
  • Teams escalate issues, believing that a problem exists.
  • Business workflows were paused or had to be handled manually.
  • Credibility with internal stakeholders took a hit.

What begins as a technical platform limit quickly becomes a business risk. We knew we needed a more scalable, transparent, and flexible solution that would work across departments and keep our communication pipelines running, even at volume.

Challenges Faced by Organizations

Once we realized Salesforce’s 5,000-email limit was blocking critical communication, we started evaluating our options. Unfortunately, every out-of-the-box or “quick fix” approach had significant trade-offs. 

Here’s what we looked at and why we ruled each out:

  • Native Workarounds: We considered queueing emails using Apex batch jobs or spacing out sends throughout the day. But the 5K cap isn’t based on timing; it’s a hard limit, and once it’s hit, no more emails go out that day. Salesforce doesn’t provide overflow queues or warnings. There’s no retry, no status tracking, and no safety net.
  • Third-Party Email Platforms: We explored using external tools like Twilio SendGrid, Cheetah Mail, or Marketing Cloud for delivery.
    However:
    • Some teams required PHI/PII-safe handling, which ruled out tools not vetted by our security architecture.
    • Other enterprise tools had integration delays or licensing limits, and we couldn’t work around them fast enough.
    • Marketing-focused platforms didn’t align with our transactional email needs (e.g., broker approval alerts).
  • Hardcoding More Logic in Apex: We could have built more flows, triggers, or Apex logic with stricter checks. But this would have:
    • Increased code maintenance burden.
    • We would have tied the email logic even more closely to Salesforce execution paths.
    • Code changes are required for every new use case or template.

After evaluating these options, we reframed the problem. We didn’t just need to ‘send more emails’; we needed to decouple email generation from delivery and make it configurable, scalable, and observable.

This realization drove our next step: building a custom, metadata-driven email staging framework that could work across multiple Salesforce objects, integrate with external systems, and give us complete control over how emails were queued, processed, and monitored.

Design Strategy

Once we realized that no existing Salesforce-native option could support our needs, we shifted from sending emails to managing email delivery as a system.

Decoupling Email Logic from Delivery

We knew our solution had to meet five non-negotiable criteria:

  1. Bypass Salesforce’s 5K Limit: The system must avoid using Messaging.sendEmail()  entirely for high-volume communications. Instead, it needed to push email data elsewhere for delivery.
  2. Be Configurable Without Deployments: We wanted teams to manage email templates, triggers, and logic using custom metadata, not Apex changes. Business agility meant turning on/off templates or object-level email logic via config.
  3. Support Multiple Salesforce Objects: The solution had to work not just for Leads or Applications, but eventually for Products, Contacts, and new objects as the system scaled.
  4. Enable Error Handling and Retry: Emails might fail due to invalid addresses, data mismatches, or integration errors. We needed a framework that tracked failures and supported retries without developer intervention.
  5. Existing Integration: Our organization already uses Intergration team, a .NET-based internal system with SMTP capabilities. We wanted Salesforce to act as the logic and staging layer, while Integration team handled the sending.

Architectural Principles We Followed 

  • Separation of concerns: Salesforce controls “what to send,” not “how to send it”.
  • Metadata over hardcoded logic: template name, method, and object triggers defined via config.
  • Modular utility classes: A single dispatcher (CH_AP_EmailUtility) routes to object-specific logic.
  • Traceability: Every email request is logged and auditable.
  • Minimal surface area for change: New emails don’t require new Apex logic.

This design strategy became the foundation of our email staging solution, a system that now supports tens of thousands of messages per week without a single sendEmail() call.

The Solution: Our Metadata-Driven Email Staging System

To meet our design goals, we built a scalable, configurable email framework centred around a custom staging object, metadata for control, and external SMTP integration.

Staging Object: Outbound_Email__c 

Instead of sending emails directly, we log each request as a record in this custom object.
Each record stores:

  • To_Email__c: Recipient address.
  • From_Email__c: Sender (default or business unit–specific).
  • Subject__c: Email subject line.
  • HTML_Body__c: Rendered HTML content.
  • Related_Record_Id__c: Lookup to Lead, Application, etc.
  • Status__c: Pending, Sent, Failed.
  • Retry_Eligible__c: Checkbox for recovery logic.
  • We use timestamps to process notes.

This allows us to queue, monitor, and retry emails, something not possible with native tools.

Metadata-Driven Logic

To make email configuration deployment-free, we use two custom metadata types:

  • Email_Template__mdt: Stores the template name, Apex class for logic, and active status. This allows centralized control of email logic.
  • OutboundEmailRelationship__mdt: Defines which objects (e.g., Application, Lead) are enabled for outbound emails and what logic should be invoked when records change.
    These metadata types empower admins to turn email workflows on/off without touching Apex.

Apex Dispatcher Class: CH_AP_EmailUtility. 

This utility handles all email creation logic. Based on metadata, it:

  • The utility searches for the appropriate Apex handler class associated with a specific object.
  • Gatherers merge data via that handler.
  • Renders the email using Messaging.renderStoredEmailTemplate().
  • Instead of sending the email directly, renderStoredEmailTemplate() creates a record in Outbound_Email__c

External SMTP Integration (Integration Team)

 Integration team is our internal .NET-based platform that runs on a schedule to:

  • Read all Outbound_Email__c records with Status = ‘Pending.’
  • Embed the HTML_Body__c into the actual email body.
  • Send via SMTP to the recipient. 
  • Update the record in Salesforce to Status = ‘Sent’ or ‘Failed.’

Because the Integration team handles the delivery, we’re free of Salesforce’s email limits.

Error Logging and Retry: Outbound_Email_Event_Tracker__c

If an email fails (due to a wrong address, template error, or SMTP issue), Integration team logs the reason in this tracker object. Admins or scheduled jobs can re-flag the original email as Retry_Eligible__c = accurate, enabling it to be reprocessed on the next run.

This architecture gave us exactly what we needed: configurable, high-volume email delivery with complete control, visibility, and scale.

Analysis

Before we started building, we didn’t jump straight into coding. We spent time auditing the problem across systems, stakeholders, and real-world workflows to ensure the solution would solve not just technical challenges but also business needs.

Use Case: We started by identifying all existing and upcoming email use cases. We reviewed Flow configurations and Apex classes using Messaging.sendEmail(), which helped us map which Salesforce objects triggered emails, such as Lead, Application, Product, and Task. We also grouped the emails by type, which included transactional alerts, onboarding instructions, and follow-up reminders. This thorough review gave us a clear picture of where emails were being generated, why they were necessary, and the patterns they followed.

Stakeholder Interviews: Stakeholder interviews had an important impact on developing the solution. We conducted working sessions with business teams from broker support, application processing, and digital outreach. We also sought advice from product owners, architects, QA teams, and compliance analysts. These conversations helped us clarify which emails were business-critical, who needed visibility into email delivery statuses, and the level of configuration flexibility each team required.

Volume and Failure Analysis: We also performed a detailed volume and failure analysis. By pulling email logs and exception reports from Salesforce, we identified patterns of silent failures. We measured both average and peak daily email volumes by object type and reviewed a backlog of tickets related to undelivered emails. This data provided a strong business case for implementing a structured retry mechanism, as well as a system that would offer visibility into email send statuses. Moreover, the data reinforced the need for configurable routing and templating logic within the system.

Metadata Modelling: Finally, we began prototyping our metadata models, including Email_Template__mdt and OutboundEmailRelationship__mdt. We listed all active templates in the organization and mapped these to the corresponding handler classes and delivery logic. One of the key aspects of our testing was ensuring that non-developers could activate or deactivate email logic via custom metadata records. This helped validate our approach before we started building, ensuring that we had a data-backed blueprint aligned with both our technical architecture goals and the day-to-day needs of the teams relying on Salesforce for timely and accurate email communications.

Outcomes

BeforeAfter
Limited to 5,000 emails per day from SalesforceCustom Staging object avoids Salesforce’s email limit
No dedicated system for logging email alertsRetry logic and error records ensure reliable email delivery
Difficult to scale email operationsSimplified scalability and integration with external systems

The results were immediate and measurable once we rolled out the metadata-driven email staging system. It didn’t just solve the 5K email limit – it fundamentally changed how our teams thought about and executed email communication from Salesforce.

No More Email Failures

By routing all outbound messages through Outbound_Email__c, we eliminated issues caused by Salesforce’s daily email cap. Business-critical messages – like broker onboarding emails, digital kit links, and application alerts – now reliably reach recipients.

End-to-End Visibility

Every email now has a lifecycle:

  • Created and stored
  • Sent or failed
  • Logged and traceable

Teams can check the status of the record itself. If something fails, they no longer submit a ticket; they can view, reprocess, or escalate with full context.

Configurable Without Deployments

Do you need to add a new email template? Turn off a specific object’s outbound messages? Change a handler class? Admins can now do all these tasks via custom metadata – no Apex changes, no deployment cycles. This increased agility across business and IT teams.

Scaling Without Friction

We now support tens of thousands of weekly emails without worrying about limits. Batch processing via Integration team allows us to scale horizontally without increasing the Salesforce load. And because the framework is metadata-based and handler-driven, it’s easy to plug in new use cases – like SMS or push notifications – without rewriting the foundation.

Internal Alignment and Ownership

We gained strong adoption across teams by involving stakeholders early and delivering precise tracking and retry functionality. Marketing, Sales, and Product now trust the email process, and IT trusts the architecture to scale cleanly.

Lessons Learned

Building and rolling out a scalable, metadata-driven email framework taught us more than just how to avoid the 5,000-email limit – it reshaped how we approach Salesforce architecture at scale.

Here are some of the most important lessons we’d share with any team considering a similar approach:

  1. Separate Email Logic from Email Delivery: Trying to handle email generation, delivery, and logging within Salesforce, especially with Messaging.sendEmail() creates fragile, hard-to-scale systems. Offloading delivery while retaining logic and status in Salesforce is the key to reliability.
  2. Metadata Makes Everything Better: From turning templates on/off to assisting Apex classes for rendering logic, metadata gave us flexibility without introducing risk. We can update the configuration without requiring a deployment or a developer.
  3. Always Build with Retry in Mind: Emails fail for insufficient data or network hiccups. A structured retry mechanism (using flags and logs) avoided many manual cleanup efforts and helped build trust in the system.
  4. One Framework, Many Use Cases: What started as a fix for broker communications is now used across lead management, product marketing, and application processing. Designing for extensibility up front saved us from rebuilding later.
  5. Traceability Builds Confidence: Giving teams visibility into what was sent, what failed, and why made adoption easier. Email logs and event trackers created a clear audit trail we’d previously lacked.

By approaching the problem as a volume limit and a design opportunity, we built a solution that serves both technical and business goals. Another organisation can also adopt this solution, given that it has the appropriate mindset, structure, and metadata foundation.

Final Thoughts

Salesforce’s 5,000-email daily limit might seem like a small constraint at first, but it quickly becomes a severe operational bottleneck for growing organizations that rely on automated communication. In our case, the critical moment prompted us to reconsider our approach to managing outbound messaging at scale. 

Through the separation of email generation from delivery, the use of metadata for logic control, and integration with an external SMTP service, we developed a solution that not only circumvented the daily limit but also enhanced reliability, visibility, and flexibility throughout the system. What began as a workaround became a scalable framework adopted by multiple teams. 

Today, business users can configure templates without needing a deployment, developers have a consistent utility to plug into, and stakeholders have complete visibility into email delivery and failures. If your org is running up against the same limitations, consider treating it as an opportunity because occasionally, a platform constraint is the push you need to design something more innovative.

The Authors

John Glennan

John is the Salesforce Developer Lead at Health Care Service Corporation.

Sanjay Gorantla

Sanjay is a Salesforce Developer Lead at HCSC, specializing in Salesforce development and CRM solutions, and is pursuing a PhD in IT.

Leave a Reply