Email Automation Guide
ECOSIRE fires automated emails on key business events and exposes an API for sending custom emails from your own workflows. This guide covers the built-in triggers, how to customize templates, and how to use ECOSIRE webhooks to trigger emails in external ESPs (Mailchimp, SendGrid, Amazon SES).
Introduction
ECOSIRE uses AWS SES in production (Mailpit in development) via React Email templates. All transactional emails are non-blocking — they never fail the primary operation.
Built-in automated emails:
| Trigger | Email sent |
|---|---|
| User signs up | Welcome email with account details |
checkout.session.completed | Purchase confirmation with download links |
| License activated | License activation confirmation |
invoice.paid (subscription renewal) | Payment receipt |
payment_intent.payment_failed | Payment failure notification |
Prerequisites
- ECOSIRE account with email configured
- For external ESP integration: Mailchimp, SendGrid, or Amazon SES account
- ECOSIRE webhook endpoint (for triggering external emails)
Step 1 — Verify Your Sending Domain
For production, configure SPF, DKIM, and DMARC on your domain:
- In AWS SES (or your ESP), verify your domain
ecosire.com. - Add DNS records:
- SPF:
v=spf1 include:amazonses.com ~all - DKIM: TXT records provided by SES
- DMARC:
v=DMARC1; p=quarantine; rua=mailto:[email protected]
- SPF:
- Confirm verification in the AWS SES Console before sending production emails.
Step 2 — Customize Email Templates
ECOSIRE email templates live in packages/email-templates/src/:
| Template | File |
|---|---|
| Welcome | welcome.tsx |
| Purchase confirmation | purchase-confirmation.tsx |
| License activation | license-activation.tsx |
| Invoice | invoice-email.tsx |
Edit a template using React Email components:
// packages/email-templates/src/welcome.tsx
import { Html, Heading, Text, Button } from '@react-email/components';
interface WelcomeEmailProps {
name: string;
loginUrl: string;
}
export function WelcomeEmail({ name, loginUrl }: WelcomeEmailProps) {
return (
<Html>
<Heading>Welcome to ECOSIRE, {name}!</Heading>
<Text>Your account is ready. Start managing your business from one place.</Text>
<Button href={loginUrl}>Go to Dashboard</Button>
</Html>
);
}
export { render } from '@react-email/components';
After editing, rebuild: pnpm build --filter=@ecosire/email-templates
Step 3 — Send a Custom Email via API
Send a one-off email using the internal Email service:
POST /api/admin/email/send
Authorization: Bearer eco_live_ADMIN_KEY
Content-Type: application/json
{
"to": "[email protected]",
"subject": "Your license is expiring soon",
"template": "license-expiry-warning",
"data": {
"name": "John",
"licenseKey": "SHOP-XXXX-XXXX-XXXX-XXXX",
"expiresAt": "2026-04-01"
}
}
This is an admin-only endpoint. For customer-facing email sends, use the automation triggers below.
Step 4 — Trigger External Emails from ECOSIRE Webhooks
Use ECOSIRE outbound webhooks to trigger emails in Mailchimp, SendGrid, or any other ESP.
Example: SendGrid on checkout.completed
import sgMail from '@sendgrid/mail';
sgMail.setApiKey(process.env.SENDGRID_API_KEY!);
app.post('/webhooks/ecosire', express.raw({ type: 'application/json' }), async (req, res) => {
// Verify signature (see Webhooks guide)
const event = JSON.parse(req.body.toString());
if (event.event === 'checkout.completed') {
const { customerEmail, lineItems } = event.data;
const productNames = lineItems.map((li: any) => li.productName).join(', ');
await sgMail.send({
to: customerEmail,
from: '[email protected]',
templateId: 'd-your-sendgrid-template-id',
dynamicTemplateData: {
customerEmail,
productNames,
orderId: event.data.orderId,
},
});
}
res.json({ received: true });
});
Step 5 — Mailchimp Tag on New Customer
When a new customer completes checkout, add them to a Mailchimp audience with tags:
import mailchimp from '@mailchimp/mailchimp_marketing';
import md5 from 'md5';
mailchimp.setConfig({ apiKey: process.env.MAILCHIMP_API_KEY!, server: 'us1' });
async function tagCustomerInMailchimp(email: string, tags: string[]) {
const listId = process.env.MAILCHIMP_LIST_ID!;
const emailHash = md5(email.toLowerCase());
// Upsert subscriber
await mailchimp.lists.setListMember(listId, emailHash, {
email_address: email,
status_if_new: 'subscribed',
status: 'subscribed',
});
// Add tags
await mailchimp.lists.updateListMemberTags(listId, emailHash, {
tags: tags.map(name => ({ name, status: 'active' })),
});
}
// In your webhook handler
if (event.event === 'checkout.completed') {
await tagCustomerInMailchimp(event.data.customerEmail, ['customer', 'shopify-connector']);
}
Step 6 — Drip Campaign on License Expiry Warning
Schedule expiry warning emails 30 days before license expiration:
// Run daily via cron
async function sendExpiryWarnings() {
const thirtyDaysOut = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString();
const res = await fetch(
`https://api.ecosire.com/api/licenses?expiringBefore=${thirtyDaysOut}&status=active&limit=100`,
{ headers: { Authorization: `Bearer ${process.env.ECOSIRE_API_KEY}` } }
);
const { data: licenses } = await res.json();
for (const license of licenses) {
if (!license.warningEmailSent) {
await sendExpiryEmail(license);
// Mark as sent to avoid duplicates (store in your DB or tag the license)
}
}
}
Troubleshooting
| Issue | Solution |
|---|---|
| Emails going to spam | Set up SPF + DKIM + DMARC; avoid spam trigger words |
| Template not found | Rebuild @ecosire/email-templates package |
| Webhook not triggering | Verify ECOSIRE webhook is registered and endpoint returns 200 |
| Mailchimp API 400 | Check email format and list ID; ensure status is subscribed |
| Duplicate emails sent | Store sent flag per event ID (use event.id as idempotency key) |
Next Steps
- Webhooks Reference — All trigger events and payloads
- Stripe Webhooks Guide — Payment event handling
- License Verification — Trigger emails on license events