Docs
Features

Email

Transactional email with Mailgun and Resend dual-service support — verification codes, order notifications, and pre-built HTML templates.

Provider Selection

# .env
EMAIL_PROVIDER="resend"   # resend | mailgun

Resend Setup

  1. Create an account at resend.com
  2. Verify your sending domain
  3. Copy your API key
# .env
RESEND_API_KEY="re_xxx"
RESEND_FROM_EMAIL="TikShip <noreply@yourdomain.com>"

Mailgun Setup

  1. Create an account at mailgun.com
  2. Add and verify your domain
  3. Copy your API key and domain
# .env
MAILGUN_API_KEY="key-xxx"
MAILGUN_DOMAIN="mg.yourdomain.com"
MAILGUN_FROM_EMAIL="TikShip <noreply@yourdomain.com>"

For production, verify your domain with the chosen provider and configure SPF/DKIM records to ensure deliverability.

Sending Emails

All email sending goes through the unified service layer, regardless of provider:

import { sendEmail } from '@/lib/email/service'

await sendEmail({
  to: 'user@example.com',
  subject: 'Welcome to TikShip',
  html: '<h1>Welcome!</h1><p>Thanks for joining.</p>',
  text: 'Welcome! Thanks for joining.',
})

With a Template

import { sendTemplateEmail } from '@/lib/email/service'

await sendTemplateEmail({
  to: user.email,
  template: 'order-confirmation',
  data: {
    orderId: 'ORD-123',
    productName: 'Pro Plan',
    amount: '$29.99',
    date: '2026-03-10',
  },
})

Pre-built Templates

TikShip ships HTML email templates for every transactional scenario:

Verification Code

Sent during registration and when a user requests a new code:

await sendTemplateEmail({
  to: user.email,
  template: 'verification-code',
  data: {
    code: '847291',
    expiresIn: '10 minutes',
  },
})

Password Reset

await sendTemplateEmail({
  to: user.email,
  template: 'password-reset',
  data: {
    resetLink: 'https://yourdomain.com/reset?token=xxx',
    expiresIn: '1 hour',
  },
})

Order Confirmation

Triggered automatically by the Stripe / PayPal webhook handler when an order reaches completed:

await sendTemplateEmail({
  to: user.email,
  template: 'order-confirmation',
  data: {
    orderId: 'ORD-123',
    productName: 'Pro Plan',
    amount: '$29.99',
    date: '2026-03-10',
  },
})

Payment Failed

Triggered automatically when an order reaches failed:

await sendTemplateEmail({
  to: user.email,
  template: 'payment-failed',
  data: {
    orderId: 'ORD-123',
    reason: 'Card declined',
    retryLink: 'https://yourdomain.com/checkout?product=xxx',
  },
})

Order Expired

Triggered automatically when a pending order reaches expired:

await sendTemplateEmail({
  to: user.email,
  template: 'order-expired',
  data: {
    orderId: 'ORD-123',
    checkoutLink: 'https://yourdomain.com/checkout?product=xxx',
  },
})

Customizing Templates

Templates live in src/lib/email/. Each template file exports TypeScript functions that return { subject, html, text }. For example, to add a welcome template:

// src/lib/email/templates-welcome.ts
export function welcomeTemplate(data: { name: string }) {
  return {
    subject: `Welcome, ${data.name}!`,
    html: `
      <div style="font-family: sans-serif; max-width: 600px; margin: 0 auto;">
        <h1>Welcome to TikShip!</h1>
        <p>Hi ${data.name}, thanks for joining.</p>
        <a href="https://yourdomain.com/dashboard"
           style="display:inline-block;padding:12px 24px;
                  background:#0070f3;color:white;
                  text-decoration:none;border-radius:6px;">
          Get Started
        </a>
      </div>
    `,
    text: `Welcome to TikShip! Hi ${data.name}, thanks for joining.`,
  }
}

Then call it from src/lib/email/service.ts like any other send call:

await sendTemplateEmail({ to: user.email, template: 'welcome', data: { name: user.name } })

Development Mode

In development, emails are logged to the console instead of being sent. Set EMAIL_PROVIDER="resend" with a test API key, or use Resend's test addresses:

delivered@resend.dev   → simulates successful delivery
bounced@resend.dev     → simulates a bounce
complained@resend.dev  → simulates a spam complaint

Best Practices

  1. Verify your domain — required for production deliverability on both Resend and Mailgun
  2. Configure SPF / DKIM — follow your provider's DNS setup guide
  3. Always include plain text — improves deliverability and accessibility
  4. Rate limit outbound sends — avoid triggering spam filters on bulk operations
  5. Expire tokens — verification codes and reset links are time-limited by default
  6. Log all sends — the email service logs provider responses; check server logs for delivery issues

Next Steps

Detailed Integration Guides

  • Mailgun & Resend Setup Guide — step-by-step walkthrough: account creation, domain verification, DNS records, API key configuration, and production checklist

Detailed Integration Guides

  • Mailgun & Resend Setup Guide — step-by-step walkthrough: account creation, domain verification, DNS records, API key configuration, and production checklist
Email | Tikship