Vertical SaaS · Workflow

Acumatica Workflow — Automated Actions and Emails

How to trigger automated actions and email notifications from Acumatica workflow transitions — using business events, notification templates, and handler code.

John Kihiu12 min read

Automated actions are the part of the Workflow engine people discover last, usually after they've already built a Business Event to send the same notification and then find out the workflow could have done it natively, at the exact moment a transition fires, without a separate subscriber to maintain. This post is about WithActions-driven automated actions specifically — not Business Events, which solve an overlapping but distinct problem and are worth understanding as the alternative.

Two different automation systems, and when each is the right one

A workflow automated action fires synchronously, as part of a specific state transition, scoped to one graph. A Business Event fires off a field change or a schedule, decoupled from any particular transition, and can span the whole platform (multiple DACs, external webhooks, Azure/Lambda targets). If the requirement is "send this email exactly when the document enters PendingApproval, every time, guaranteed" — that's a workflow automated action, tied directly to the transition, and it can't silently get disabled the way a Business Event subscriber can be deactivated without anyone noticing on the Workflow screen where the rest of the transition logic lives. If the requirement is "notify an external system whenever this field changes, regardless of which screen changed it," that's a Business Event.

Wiring an email action to a transition

Automated actions attach at the transition level via .WithActions() on the transition builder, referencing a notification template configured on the Notification Templates screen (SM204003):

C#
graph.WithTransitions(transitions => transitions
    .AddGroupFrom<APInvoice.status.Balanced>(g => g
        .Add(t => t
            .To<APInvoice.status.PendingApproval>()
            .IsTriggeredOn(a => a.Actions.Release)
            .When(APInvoice.docTotal.IsGreaterEqual(5000m))
            .WithActions(a => a
                .Add(c => c.SendNotification(
                    notificationCd: "APBILL-PENDING-APPROVAL",
                    recipientsDelegate: g2 => ResolveApprovers(g2.Document.Current))))
        )));

The notification template itself is built and maintained on the Notification/Email Templates screens, not in code — the workflow only decides when it fires and, if you need dynamic recipients beyond what the template's own recipient configuration supports, supplies the resolved recipient list at trigger time.

Automated actions run once per transition, not once per document lifetime

A gotcha specific to automated actions: if a document transitions into the same state twice — say, an approval is rejected, the document returns to a prior state, and a resubmission triggers the same transition again — the automated action fires again too, sending a second "pending approval" email for what feels to the user like a re-submission, not a first submission. If the template language doesn't distinguish ("Your bill needs approval" reads oddly on attempt two), add a resubmission counter field and either branch the notification template content on it or use a variant transition path specifically for resubmissions, similar to how tiered approval states are kept distinct elsewhere in this series.

Test the reject-then-resubmit path explicitly

The happy path (submit once, approve once) always looks right in a demo. The path that actually generates support tickets is reject, edit, resubmit — walk it manually before calling an automated-action wiring done, and check both the email content and that recipients are re-resolved correctly (the original approver might not be the right one the second time if the document changed materially).

Automated actions aren't limited to email

The same .WithActions() hook can call any method on the graph, not just SendNotification — updating a field, calling out to another graph, or invoking a custom method that posts to an external system synchronously as part of the transition:

C#
.WithActions(a => a
    .Add(c => c.SetValueExt<APInvoice.approvalRequestedDate>(
        c.Document.Current, DateTime.Now))
    .Add(c => c.SendNotification("APBILL-PENDING-APPROVAL", ResolveApprovers)))

Keep these fast and side-effect-light — a transition is part of the user's Save/Release click, so an automated action that calls a slow external API synchronously makes every approval submission feel sluggish. For anything beyond a quick field update or an email queue insert, fire a Business Event or a background processing item from the transition instead of doing the slow work inline.

Let the template resolve static recipients; resolve dynamic ones in code

If the recipient is always "the AP manager role," configure that directly on the Notification Template's recipient list — no code needed. Only drop into a recipient delegate in WithActions when the recipient genuinely depends on document data the template's own configuration can't express (the conditional-assignment patterns covered elsewhere in this series apply here too — resolve into a field, or compute the list directly in the delegate, rather than fighting the template's static recipient UI into doing something dynamic it isn't built for).

Wrapping up

Automated actions are the right tool when a notification or side effect must happen exactly once per specific transition, guaranteed, visible right there on the same diagram as the rest of the state logic — reach for a Business Event instead when the trigger isn't really transition-shaped. Keep the action itself fast, test resubmission paths explicitly since they're the ones nobody demos, and only reach for a recipient delegate when the template's static configuration genuinely can't express the resolution rule.

John Kihiu
Acumatica ERP Developer · Laravel Engineer

Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.