IntegrationsCommunication
Multi-provider email integration for Gmail, Outlook, Resend, and SendGrid
Send emails through multiple providers with unified configuration and Handlebars template support.
Overview
The Email integration is a building block that supports multiple email providers:
- Gmail - Google Workspace email via OAuth
- Outlook - Microsoft 365 email via OAuth
- Resend - Developer-friendly email API
- SendGrid - Transactional email platform
Prerequisites
| Provider | Requirements |
|---|---|
| Gmail | Google Workspace account, OAuth connection via Nango |
| Outlook | Microsoft 365 account, OAuth connection via Nango |
| Resend | Resend account, API key |
| SendGrid | SendGrid account, API key connection via Nango |
Authentication
Gmail / Outlook (OAuth)
# Gmail
curl "http://localhost:3000/api/v1/connections/google-mail/auth-url" \
-H "x-api-key: YOUR_API_KEY"
# Outlook
curl "http://localhost:3000/api/v1/connections/microsoft-graph/auth-url" \
-H "x-api-key: YOUR_API_KEY"Resend (API Key)
Set the RESEND_API_KEY environment variable or pass api_key in the step config.
SendGrid (API Key via Nango)
curl "http://localhost:3000/api/v1/connections/sendgrid/auth-url" \
-H "x-api-key: YOUR_API_KEY"Email Step Configuration
The email step uses type email in workflow definitions:
{
"id": "send-notification",
"type": "email",
"name": "Send Invoice Email",
"config": {
"action": "send",
"provider": "gmail",
"to": "{{input.customer_email}}",
"subject": "Invoice #{{input.invoice_number}}",
"body": {
"html": "<p>Hello {{input.customer_name}},</p><p>Your invoice is ready.</p>"
}
}
}Available Actions
send
Send an email immediately.
{
"id": "send-email",
"type": "email",
"config": {
"action": "send",
"provider": "gmail",
"to": "{{input.recipient}}",
"cc": ["manager@company.com"],
"bcc": ["archive@company.com"],
"from": "notifications@company.com",
"reply_to": "support@company.com",
"subject": "Your Order #{{input.order_number}} Has Shipped",
"body": {
"html": "<h1>Order Shipped!</h1><p>Hi {{input.customer_name}},</p><p>Your order is on its way.</p>",
"text": "Order Shipped! Hi {{input.customer_name}}, Your order is on its way."
},
"attachments": [
{
"filename": "shipping-label.pdf",
"content": "{{input.label_base64}}",
"content_type": "application/pdf"
}
],
"headers": {
"X-Order-ID": "{{input.order_id}}"
},
"priority": "1"
}
}Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
action | string | Yes | Must be send |
provider | string | Yes | gmail, outlook, resend, sendgrid |
to | string/array | Yes | Recipient email(s) |
cc | array | No | CC recipients |
bcc | array | No | BCC recipients |
from | string | No | Sender address |
reply_to | string | No | Reply-to address |
subject | string | Yes | Email subject (supports templates) |
body.html | string | No | HTML body (supports templates) |
body.text | string | No | Plain text body (supports templates) |
attachments | array | No | File attachments |
headers | object | No | Custom email headers |
priority | string | No | Priority (1=high, 3=normal, 5=low) |
template_variables | object | No | Additional template variables |
sendTemplate
Send using a server-side template (SendGrid only).
{
"id": "send-template",
"type": "email",
"config": {
"action": "send_template",
"provider": "sendgrid",
"to": "{{input.email}}",
"from": "noreply@company.com",
"template": {
"id": "d-abc123def456",
"variables": {
"first_name": "{{input.first_name}}",
"order_total": "{{input.total}}",
"items": "{{input.line_items}}"
}
}
}
}Note: Gmail and Outlook do not support server-side templates. Use inline Handlebars templates with the send action instead.
schedule
Schedule an email for later delivery.
{
"id": "schedule-reminder",
"type": "email",
"config": {
"action": "schedule",
"provider": "sendgrid",
"to": "{{input.email}}",
"subject": "Reminder: Your appointment tomorrow",
"body": {
"html": "<p>Hi {{input.name}}, this is a reminder about your appointment.</p>"
},
"send_at": "{{input.reminder_time}}"
}
}Scheduling Support:
| Provider | Native Scheduling |
|---|---|
| SendGrid | ✅ Yes |
| Resend | ✅ Yes |
| Gmail | ❌ No (use Trigger.dev scheduled tasks) |
| Outlook | ❌ No (use Trigger.dev scheduled tasks) |
Handlebars Templates
The email integration uses Handlebars for dynamic content:
Basic Variables
Hello {{input.customer_name}},
Your order #{{input.order_number}} has been confirmed.Conditionals
{{#if input.is_premium}}
<p>Thank you for being a Premium member!</p>
{{else}}
<p>Upgrade to Premium for exclusive benefits.</p>
{{/if}}Loops
<h2>Order Items:</h2>
<ul>
{{#each input.items}}
<li>{{this.name}} - ${{this.price}} x {{this.quantity}}</li>
{{/each}}
</ul>Nested Properties
Shipping to: {{input.shipping.address.city}}, {{input.shipping.address.state}}Provider-Specific Features
Gmail
- Uses RFC 2822 message format
- Supports threading via
in_reply_toandreferences - Full attachment support with base64 encoding
{
"config": {
"provider": "gmail",
"in_reply_to": "{{input.original_message_id}}",
"references": ["{{input.thread_message_id}}"]
}
}Outlook
- Uses Microsoft Graph API
- Saves sent emails to Sent Items
- Supports importance levels
{
"config": {
"provider": "outlook",
"priority": "1"
}
}Resend
- Simple API-first design
- Direct API calls (no Nango required)
- Supports scheduling
{
"config": {
"provider": "resend",
"api_key": "{{env.RESEND_API_KEY}}"
}
}SendGrid
- Server-side templates with dynamic data
- Open and click tracking
- Scheduling support
{
"config": {
"provider": "sendgrid",
"tracking": {
"opens": true,
"clicks": true
}
}
}Example Workflow
Invoice email workflow:
{
"name": "Send Invoice Email",
"trigger": {
"type": "webhook",
"provider": "stripe",
"events": ["invoice.finalized"]
},
"steps": [
{
"id": "get-customer",
"type": "action",
"action": "stripe.getCustomer",
"config": {
"customerId": "{{input.data.object.customer}}"
}
},
{
"id": "send-invoice-email",
"type": "email",
"name": "Email Invoice to Customer",
"config": {
"action": "send",
"provider": "gmail",
"to": "{{steps.get-customer.output.email}}",
"subject": "Invoice #{{input.data.object.number}} from {{company.name}}",
"body": {
"html": "<h1>Invoice Ready</h1><p>Hi {{steps.get-customer.output.name}},</p><p>Your invoice for <strong>${{input.data.object.amount_due | divided_by: 100}}</strong> is ready.</p><p><a href=\"{{input.data.object.hosted_invoice_url}}\">View Invoice</a></p><p>Due date: {{input.data.object.due_date | date: 'MMMM D, YYYY'}}</p>"
}
}
},
{
"id": "notify-finance",
"type": "action",
"action": "slack.sendMessage",
"config": {
"channel": "#finance",
"text": "Invoice #{{input.data.object.number}} sent to {{steps.get-customer.output.email}}"
}
}
]
}Attachments
Base64 Content
{
"attachments": [
{
"filename": "report.pdf",
"content": "{{steps.generate-pdf.output.base64}}",
"content_type": "application/pdf"
}
]
}Multiple Attachments
{
"attachments": [
{
"filename": "invoice.pdf",
"content": "{{input.invoice_pdf}}",
"content_type": "application/pdf"
},
{
"filename": "terms.pdf",
"content": "{{env.TERMS_PDF_BASE64}}",
"content_type": "application/pdf"
}
]
}Rate Limits
| Provider | Limit |
|---|---|
| Gmail | 2,000 messages/day (free), higher for Workspace |
| Outlook | 10,000 messages/day |
| Resend | Based on plan |
| SendGrid | Based on plan |
Troubleshooting
Common Errors
| Error | Cause | Solution |
|---|---|---|
connectionId is required | No OAuth connection | Set up connection via Nango |
Resend API key not found | Missing API key | Set RESEND_API_KEY env var |
template is required | Using sendTemplate without template | Provide template.id |
provider does not support server-side templates | Gmail/Outlook with sendTemplate | Use send action with inline templates |
provider does not support native scheduling | Gmail/Outlook with schedule | Use Trigger.dev scheduled tasks |
Template Rendering Issues
- Ensure all template variables exist in the context
- Use
{{#if variable}}for optional fields - Check for typos in variable paths