Skip to main content

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:

TriggerEmail sent
User signs upWelcome email with account details
checkout.session.completedPurchase confirmation with download links
License activatedLicense activation confirmation
invoice.paid (subscription renewal)Payment receipt
payment_intent.payment_failedPayment 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:

  1. In AWS SES (or your ESP), verify your domain ecosire.com.
  2. 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]
  3. 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/:

TemplateFile
Welcomewelcome.tsx
Purchase confirmationpurchase-confirmation.tsx
License activationlicense-activation.tsx
Invoiceinvoice-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

IssueSolution
Emails going to spamSet up SPF + DKIM + DMARC; avoid spam trigger words
Template not foundRebuild @ecosire/email-templates package
Webhook not triggeringVerify ECOSIRE webhook is registered and endpoint returns 200
Mailchimp API 400Check email format and list ID; ensure status is subscribed
Duplicate emails sentStore sent flag per event ID (use event.id as idempotency key)

Next Steps