Transactional Emails

Send transactional emails for user actions: welcome emails, password resets, order confirmations, receipts, and more. Built for reliability with tracking and analytics.

What are Transactional Emails?

Transactional emails are triggered by user actions and contain information specific to that user. Unlike marketing emails (broadcasts), they are:

🎯 Triggered

Sent automatically based on user actions like signing up, making a purchase, or resetting a password.

👤 Personalized

Contain information specific to the recipient like their name, order details, or account information.

⚡ Time-Sensitive

Expected immediately after the action. Delivery speed is critical for user experience.

Common Transactional Email Types

TypeTriggerPriority
Welcome EmailUser registrationHigh
Email VerificationAccount creationHigh
Password ResetForgot password requestCritical
Order ConfirmationPurchase completedHigh
Shipping NotificationOrder shippedMedium
Receipt/InvoicePayment processedMedium
Account ActivityLogin, changes, etc.Medium

Quick Examples

welcome-email.tsTypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import Metigan from 'metigan';

const metigan = new Metigan({
  apiKey: process.env.METIGAN_API_KEY!
});

async function sendWelcomeEmail(user: { email: string; name: string }) {
  const result = await metigan.email.sendEmail({
    from: 'Welcome Team <welcome@myapp.com>',
    recipients: [user.email],
    subject: `Welcome to MyApp, ${user.name}! 🎉`,
    content: `
      <!DOCTYPE html>
      <html>
        <body style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px;">
          <div style="text-align: center; padding: 40px 0;">
            <h1 style="color: #2563eb; margin: 0;">Welcome, ${user.name}! 👋</h1>
          </div>
          
          <p style="font-size: 16px; line-height: 1.6; color: #374151;">
            Thank you for joining MyApp! We're excited to have you on board.
          </p>
          
          <div style="background: #f3f4f6; border-radius: 8px; padding: 20px; margin: 30px 0;">
            <h3 style="margin: 0 0 15px 0; color: #1f2937;">Getting Started:</h3>
            <ul style="margin: 0; padding-left: 20px; color: #4b5563;">
              <li style="margin-bottom: 10px;">Complete your profile</li>
              <li style="margin-bottom: 10px;">Explore our features</li>
              <li style="margin-bottom: 10px;">Invite your team</li>
            </ul>
          </div>
          
          <div style="text-align: center; margin: 30px 0;">
            <a href="https://myapp.com/dashboard" 
               style="display: inline-block; padding: 14px 28px; background: #2563eb; color: white; 
                      text-decoration: none; border-radius: 8px; font-weight: 600;">
              Go to Dashboard →
            </a>
          </div>
          
          <p style="font-size: 14px; color: #6b7280; border-top: 1px solid #e5e7eb; padding-top: 20px;">
            Questions? Reply to this email or contact support@myapp.com
          </p>
        </body>
      </html>
    `
  });

  return result;
}

// On user registration
sendWelcomeEmail({ email: 'newuser@example.com', name: 'John' });

Using Templates with Variables

For cleaner code and easier maintenance, use templates with dynamic variables. Create the template once, then just pass the data when sending.

Step 1: Create Template

create-transactional-template.tsTypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import Metigan from 'metigan';

const metigan = new Metigan({
  apiKey: process.env.METIGAN_API_KEY!
});

// Create a welcome email template with variables
const template = await metigan.templates.create({
  name: 'Welcome Email',
  subject: 'Welcome to {{appName}}, {{firstName}}! 🎉',
  content: `
    <!DOCTYPE html>
    <html>
      <body style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px;">
        <h1>Welcome, {{firstName}} {{lastName}}! 👋</h1>
        
        <p>Thank you for joining {{appName}}!</p>
        
        <p>Your account details:</p>
        <ul>
          <li>Email: {{email}}</li>
          <li>Plan: {{plan}}</li>
        </ul>
        
        <a href="{{dashboardUrl}}" style="display: inline-block; padding: 14px 28px; 
           background: #2563eb; color: white; text-decoration: none; border-radius: 8px;">
          Go to Dashboard
        </a>
        
        <p style="margin-top: 30px; color: #6b7280; font-size: 14px;">
          Need help? Contact us at {{supportEmail}}
        </p>
      </body>
    </html>
  `
});

console.log('Template ID:', template.id);
// Save: WELCOME_TEMPLATE_ID = template.id

Step 2: Send with Variables

send-with-variables.tsTypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import Metigan from 'metigan';

const metigan = new Metigan({
  apiKey: process.env.METIGAN_API_KEY!
});

const WELCOME_TEMPLATE_ID = 'your-template-id';

async function sendWelcomeEmail(user: {
  email: string;
  firstName: string;
  lastName: string;
  plan: string;
}) {
  const result = await metigan.email.sendEmail({
    from: 'Welcome <welcome@myapp.com>',
    recipients: [user.email],
    templateId: WELCOME_TEMPLATE_ID,
    variables: {
      firstName: user.firstName,
      lastName: user.lastName,
      email: user.email,
      plan: user.plan,
      appName: 'MyApp',
      dashboardUrl: 'https://myapp.com/dashboard',
      supportEmail: 'support@myapp.com'
    }
  });

  return result;
}

// Usage
sendWelcomeEmail({
  email: 'john@example.com',
  firstName: 'John',
  lastName: 'Doe',
  plan: 'Pro'
});
Template Variables

Use {{variableName}} syntax in your templates. All variables passed in the variables object will be automatically replaced when sending.

Best Practices

📧 Email Design

  • • Keep emails simple and focused
  • • Use inline CSS for compatibility
  • • Test on multiple email clients
  • • Mobile-first design (600px max-width)
  • • Clear call-to-action buttons
  • • Include plain text fallback

⚡ Delivery

  • • Send immediately after trigger event
  • • Use verified sender domains
  • • Implement retry logic for failures
  • • Monitor delivery rates
  • • Use tracking IDs for debugging
  • • Set up webhooks for status updates

🔒 Security

  • • Never include passwords in emails
  • • Use short expiry for sensitive links
  • • Generate secure random tokens
  • • Validate email addresses
  • • Implement rate limiting
  • • Log sending events (not content)

📊 Tracking

  • • Use tracking IDs for each email
  • • Set up webhooks for open/click events
  • • Monitor bounce and complaint rates
  • • A/B test subject lines
  • • Track conversion rates
  • • Analyze engagement metrics

Tracking with Webhooks

Set up webhooks to receive real-time notifications about email events:

webhook-handler.tsTypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// Express webhook handler for email events
app.post('/webhooks/metigan', (req, res) => {
  const event = req.body;
  
  switch (event.event) {
    case 'email.delivered':
      console.log(`Email ${event.trackingId} delivered to ${event.recipient}`);
      // Update your database
      break;
      
    case 'email.opened':
      console.log(`Email ${event.trackingId} opened`);
      // Track engagement
      break;
      
    case 'email.clicked':
      console.log(`Link clicked in email ${event.trackingId}`);
      // Track conversion
      break;
      
    case 'email.bounced':
      console.log(`Email bounced: ${event.recipient}`);
      // Mark email as invalid, stop sending
      break;
      
    case 'email.complained':
      console.log(`Spam complaint from ${event.recipient}`);
      // Unsubscribe user immediately
      break;
  }
  
  res.status(200).send('OK');
});
Learn More

See the Webhook Integration Guide for complete setup instructions and event types.

Related Guides