A workflow watches for something happening in Nylas and sends an email when it does. A booking is made, a meeting gets recorded, an account stops syncing, and the right person hears about it without you writing a webhook handler or a send call.
Every recipe in this section follows the same shape. This page covers the parts they share: the objects involved, the triggers available, and the one constraint that decides which triggers you can safely build on.
What are Nylas Workflows?
Section titled “What are Nylas Workflows?”A workflow binds one trigger event to one email template and one sender address. When the event fires, Nylas renders the template against the event payload and sends the result. There’s no code step in between, so a workflow can send email and nothing else.
Three objects are involved, created in this order:
| Object | Holds | Endpoint |
|---|---|---|
| Template | Subject and HTML body with {{variable}} placeholders | /v3/templates |
| Workflow | Trigger event, template ID, sender, delay | /v3/workflows |
| Trigger source | The Scheduler configuration, Notetaker session, or grant that produces the event | varies by recipe |
The template does the work. Every field in the event payload is available as a variable, so the email can name the meeting, format the time in the recipient’s timezone, and link to the recording. Templates and workflows documents the variable model and the formatDate helper.
Which events can trigger a workflow?
Section titled “Which events can trigger a workflow?”Workflows accept 34 trigger events across 9 categories, covering Scheduler, Notetaker, the calendar, the mailbox, and the account lifecycle.
| Category | Triggers |
|---|---|
| Scheduler | booking.created, booking.pending, booking.rescheduled, booking.cancelled, booking.reminder |
| Notetaker | notetaker.created, notetaker.updated, notetaker.deleted, notetaker.meeting_state, notetaker.media |
| Grants | grant.created, grant.updated, grant.expired, grant.deleted, grant.imap_sync_completed |
| Events | event.created, event.updated, event.deleted |
| Calendar | calendar.created, calendar.updated, calendar.deleted |
| Folders | folder.created, folder.updated, folder.deleted |
| Messages | message.created, message.updated, message.send_success, message.send_failed, message.bounce_detected |
| Message tracking | message.opened, message.link_clicked, thread.replied |
| Contacts | contact.updated, contact.deleted |
Every trigger except 2 accepts either sender: omit from to send from the mailbox of the grant that triggered the event, or set from to send through transactional send on your verified domain. grant.expired and grant.deleted require from, because the grant that triggered them can no longer send mail.
The deliverability triggers aren’t available. message.transactional.bounced, message.transactional.complaint, message.transactional.delivered, message.transactional.rejected, and the 4 equivalent Agent Accounts triggers are all rejected. Handle those through a webhook and your suppression list instead, because answering a bounce or a complaint with another email is the wrong response.
Which triggers are safe to build on?
Section titled “Which triggers are safe to build on?”Workflows don’t filter. An enabled workflow sends once for every matching event in its scope, so the trigger’s natural volume is the volume of email your recipients get. A template can change its wording with eq, but it can’t skip the send.
| Volume | Triggers | Suitable for |
|---|---|---|
| One per deliberate action | booking.*, grant.*, notetaker.* | Customer-facing email. Start here. |
| One per calendar change | event.*, calendar.* | Customer-facing email, if your users’ calendars aren’t busy |
| One per message | message.created, message.updated, message.opened, message.link_clicked, thread.replied | Internal alerts, or grant-level workflows on low-volume mailboxes. See below. |
The message triggers are the ones to size first. A message.created workflow sends once per message arriving in every connected mailbox in scope, so on an application with a few thousand grants that’s thousands of sends an hour from your domain. Use a webhook when you need to decide per event whether to send, and workflows when every occurrence of the event deserves an email.
Should the workflow live on the application or the grant?
Section titled “Should the workflow live on the application or the grant?”Application-level workflows fire for every grant in the application and are managed from the Dashboard. Grant-level workflows fire for a single grant and let each of your customers have their own branding, at the cost of creating and maintaining one workflow per grant.
| Application-level | Grant-level | |
|---|---|---|
| Endpoint | POST /v3/workflows | POST /v3/grants/{grant_id}/workflows |
| Fires for | Every grant in the application | One grant |
| How many to manage | 1 per trigger | 1 per trigger per grant |
| Visible in the Dashboard | Yes | No |
| Good for | One product voice for all users | Per-customer branding and copy |
Both levels fire independently. An application-level workflow and a grant-level workflow on the same trigger produce 2 messages to the same person, and because the Dashboard lists only application-level workflows, the grant-level one is easy to forget. If a recipient reports duplicate email, list both scopes before anything else.
Customize Scheduler email for your app and Customize Scheduler email for each user work through the same feature at both levels, including what per-customer templates cost to run.
Which sender should the workflow use?
Section titled “Which sender should the workflow use?”A workflow sends from one of 2 places, and the choice is the first thing to settle. Omit from and the message goes out through the grant that triggered the event, from that user’s real mailbox. Set from and it goes through transactional send on a domain you registered with Nylas.
| Send from the grant | Transactional send | |
|---|---|---|
Set from? | no | yes |
| Appears to come from | the user’s own address | your product’s domain |
| Setup needed | mail send scopes on the grant | a registered domain and 4 DNS records |
| Replies go to | the user’s mailbox | wherever your domain routes |
| Lands in the user’s Sent folder | yes | no |
| Counts against the provider’s sending limits | yes | no |
| Still works when the grant breaks | no | yes |
Send from the grant when the message should look like it came from a person. A Scheduler confirmation from the host’s own address reads like the host sent it, arrives in the same thread as their other correspondence, and puts replies in the host’s inbox where they expect them. It also needs no domain setup at all, which makes it the fastest path to a working workflow.
Use transactional send when the message is from your product rather than from a person, when you need consistent branding across every customer, or when you can’t rely on the grant. Account lifecycle email is the clearest case: a reconnect prompt can’t go through the mailbox that just stopped working.
Two triggers have no choice. grant.expired and grant.deleted require from, and return 400 This event type requires transactional send. Please provide a sender email address. without it, for exactly that reason.
Grant sending goes out through the provider’s own API rather than through Nylas infrastructure. On a Google grant, a message sent this way arrives with Received: by gmailapi.google.com with HTTPREST, a Gmail-issued Message-Id, and no Reply-To, so replies return to the sender’s address. Because it’s a real send from that mailbox, it’s subject to the provider’s per-mailbox sending limits in a way transactional send isn’t.
The failure mode for grant sending is quiet. A grant authenticated with identity-only scopes can’t send mail, so the workflow writes Grant is not valid or does not have required scopes to send emails to the log, delivers nothing, and returns no error to you. If you rely on grant sending, check the scopes when the grant is created rather than when a user reports a missing email.
What do I need before I start?
Section titled “What do I need before I start?”An API key, a template, and, if you chose transactional send above, a registered sending domain. Workflows that send through the grant need no domain setup, so skip ahead and go straight to creating the workflow.
This is the same domain registration that Nylas Agent Accounts use, with one difference: workflows only send, so you only publish the outbound records. Nylas tracks 5 verification types, and send-only needs 4 of them.
| Type | Record | Needed for workflows | Needed for Agent Accounts |
|---|---|---|---|
ownership | TXT | yes | yes |
dkim | TXT | yes | yes |
spf | TXT | yes | yes |
feedback | MX | yes | yes |
mx | MX | no | yes |
The mx type is the one to leave off. It routes inbound mail to Nylas, so on a domain that already receives email it replaces the MX records pointing at Google Workspace or Microsoft 365. Skip it and your existing mail keeps flowing untouched while the domain sends through Nylas. Add it only when you also want Agent Accounts receiving replies at that domain.
The feedback MX is safe despite being an MX record, because it goes on a subdomain used as the return path rather than on the domain you receive mail at.
Register through the Dashboard or the API
Section titled “Register through the Dashboard or the API”Use the Dashboard if you’re setting up one domain for your own product. It lists every record with a copy button and a Copy zone file button that copies them all at once.
Use the Manage Domains API when your customers bring their own sending domains and you want the flow inside your product. The sequence is 3 calls:
# 1. register the domainPOST /v3/admin/domains
# 2. fetch the DNS records to show the customer, once per verification typePOST /v3/admin/domains/{domain_id}/info
# 3. check them once the customer has published themPOST /v3/admin/domains/{domain_id}/verifyOne thing to plan for: the Manage Domains API uses Nylas Service Account authentication, which signs each request with the X-Nylas-Kid, X-Nylas-Timestamp, X-Nylas-Nonce, and X-Nylas-Signature headers. A plain API key returns 401 Nonce is required, so this runs from your own server with credentials Nylas issues separately, not from the same key your workflow calls use. The API also needs a contract that includes domain management. Nylas Support issues the Service Account credentials.
Some record values expire, so call /info again for fresh values rather than caching what you showed the customer last week. Nylas recommends a subdomain such as mail.example.com for sending, which keeps the records away from your main domain.
Create the workflow
Section titled “Create the workflow”Decide which of the 2 senders the workflow uses, because it changes what you have to set up and what the recipient sees. Omitting from sends through the grant that fired the event, so the message comes from that user’s own mailbox. Setting from sends through transactional send on a domain you registered, so it comes from your product.
curl -X POST 'https://api.us.nylas.com/v3/workflows' \ -H "Authorization: Bearer $NYLAS_API_KEY" -H 'Content-Type: application/json' \ -d '{ "name": "Booking confirmed", "trigger_event": "booking.created", "template_id": "<TEMPLATE_ID>", "delay": 0, "is_enabled": true, "from": { "email": "[email protected]", "name": "Your Company" } }'delay is in minutes and 0 sends immediately. Set a delay when the recipient might act before the email is useful, such as a reconnect prompt that would cross with the user reconnecting.
Recipes
Section titled “Recipes”Scheduler
- Customize Scheduler email for your app replaces the built-in booking email for every user
- Customize Scheduler email for each user gives each customer their own branding
- Tell Scheduler attendees the meeting is recorded pairs a booking with Notetaker
Calendar
- Email attendees when a meeting is booked covers meetings created through the Events API
- Tell Events API attendees the meeting is recorded does the same for calendar-created meetings
Notetaker
- Send the recording when Notetaker media is ready delivers the recording and transcript
- Tell the host when Notetaker couldn’t join catches waiting-room failures
Accounts
- Welcome users when they connect an account confirms what was granted
- Reduce churn by catching inactive accounts recovers grants before the user leaves
Debugging
- Why isn’t my workflow sending email? covers the silent failure everyone hits first