FAQs

Can I call transactional email actions from async Apex or a batch?

Building custom Apex to trigger transactional emails in bulk is a common pattern, and our SendSmartEmail invocable action is designed to work asynchronously. That said, there are a few common mistakes in how the batch is structured that can cause emails to fail silently or errors to appear in your maintenance logs.

Before diving into the batch structure, make sure the running user has at least the Campaign Monitor Limited User permission set assigned. They'll also need read access to any fields used in your template mappings, and if Opt Out is enabled, access to the opt out field as well.

If you're seeing errors, check the CM Settings tab in Salesforce and review the Maintenance Logs section, which captures issues we can detect on our end.

The Solution

Our action is built to handle async workloads, so the issue is almost always how the batch is structured. Here are the most common mistakes to check:

Only call sendEmail once, after the for loop
Build up your list of SendSmartEmailRequest objects inside the execute method, but don't call SendSmartEmail.sendEmail() there. Save the full list and call it once from the finish method.

Call from finish, not execute
The execute method runs in chunks. Calling the action there risks hitting callout limits. The finish method runs once and is the right place to fire the email action.

Set the correct RootObject
The RootObject on your request must match the mapping object on your Smart Email template (usually Contact). A mismatch will cause the action to fail.

Use direct = false for large sends
For large batches, set direct = false on your requests. This avoids callout limit errors by letting Campaign Monitor handle delivery asynchronously.

The general flow looks like this:

  • A Schedulable class (running as a user with the correct permission set) kicks off your welcome batch
  • The batch execute method builds the SendSmartEmailRequest list only
  • The batch finish method calls SendSmartEmail.sendEmail(requests) once
  • That starts SendSmartEmailBatch, which handles delivery through Campaign Monitor

We don't offer support for custom code builds, but if you've reviewed the above and are still seeing issues, check the Maintenance Logs on the CM Settings tab for any errors we've caught on our end.

Related Articles

Related articles
How to guides
Contact Us