emailr_
All articles
usecaseยท8 min

Shipping notification emails: Best practices

ecommercenotificationstracking

Shipping notifications reduce support tickets and build customer confidence. Here's how to design effective shipping emails throughout the delivery journey.

Shipping email sequence

Order shipped

interface ShippingNotification {
  order: {
    id: string;
    items: OrderItem[];
  };
  shipping: {
    carrier: string;
    trackingNumber: string;
    trackingUrl: string;
    estimatedDelivery: Date;
    shippedAt: Date;
  };
  customer: {
    name: string;
    email: string;
  };
  address: ShippingAddress;
}

await sendEmail({
  to: customer.email,
  subject: `Your order has shipped! ๐Ÿ“ฆ`,
  template: 'order-shipped',
  data: {
    customer,
    order,
    shipping,
    trackingUrl: shipping.trackingUrl,
    estimatedDelivery: formatDate(shipping.estimatedDelivery)
  }
});

Out for delivery

await sendEmail({
  to: customer.email,
  subject: 'Your order is out for delivery! ๐Ÿšš',
  template: 'out-for-delivery',
  data: {
    customer,
    order,
    estimatedWindow: '2:00 PM - 6:00 PM',
    trackingUrl: shipping.trackingUrl
  }
});

Delivered confirmation

await sendEmail({
  to: customer.email,
  subject: 'Your order has been delivered โœ“',
  template: 'order-delivered',
  data: {
    customer,
    order,
    deliveredAt: shipping.deliveredAt,
    deliveryPhoto: shipping.proofOfDelivery,
    reviewUrl: `${baseUrl}/orders/${order.id}/review`,
    supportUrl: `${baseUrl}/support`
  }
});

Exception handling

Delivery exception

const exceptionTemplates = {
  'address_issue': {
    subject: 'Delivery issue - address update needed',
    template: 'delivery-exception-address'
  },
  'recipient_unavailable': {
    subject: 'Delivery attempted - no one home',
    template: 'delivery-exception-unavailable'
  },
  'weather_delay': {
    subject: 'Shipping delay due to weather',
    template: 'delivery-exception-weather'
  }
};

async function sendExceptionNotification(order: Order, exception: DeliveryException) {
  const config = exceptionTemplates[exception.type];
  
  await sendEmail({
    to: order.customer.email,
    subject: config.subject,
    template: config.template,
    data: {
      order,
      exception,
      newEstimate: exception.newEstimatedDelivery,
      actionRequired: exception.requiresAction,
      updateUrl: `${baseUrl}/orders/${order.id}/update-address`
    }
  });
}

Failed delivery

await sendEmail({
  to: customer.email,
  subject: 'Delivery unsuccessful - action required',
  template: 'delivery-failed',
  data: {
    customer,
    order,
    reason: exception.reason,
    options: [
      { label: 'Reschedule delivery', url: rescheduleUrl },
      { label: 'Update address', url: updateAddressUrl },
      { label: 'Hold at facility', url: holdUrl }
    ],
    deadline: 'Package will be returned after 5 days'
  }
});

Multi-package orders

interface MultiPackageShipment {
  order: Order;
  packages: Array<{
    packageNumber: number;
    totalPackages: number;
    trackingNumber: string;
    items: OrderItem[];
    status: string;
  }>;
}

await sendEmail({
  to: customer.email,
  subject: `Package 1 of 3 shipped - Order #${order.number}`,
  template: 'multi-package-shipped',
  data: {
    customer,
    order,
    package: packages[0],
    remainingPackages: packages.slice(1),
    allTrackingUrl: `${baseUrl}/orders/${order.id}/tracking`
  }
});

Carrier integration

Webhook handling

async function handleCarrierWebhook(event: CarrierEvent) {
  const order = await getOrderByTracking(event.trackingNumber);
  
  const eventMap = {
    'shipped': sendShippedNotification,
    'in_transit': sendTransitUpdate,
    'out_for_delivery': sendOutForDeliveryNotification,
    'delivered': sendDeliveredNotification,
    'exception': sendExceptionNotification
  };
  
  const handler = eventMap[event.status];
  if (handler) {
    await handler(order, event);
  }
}

Best practices

  1. โ€”Real-time updates - Send as soon as status changes
  2. โ€”Clear tracking links - One click to carrier tracking
  3. โ€”Set expectations - Estimated delivery windows
  4. โ€”Handle exceptions - Proactive communication on delays
  5. โ€”Include order details - Remind them what's coming
  6. โ€”Mobile-friendly - Most check shipping on phones

Good shipping emails reduce "where's my order?" support tickets and build customer confidence.

โ€ข
e_

Written by the emailr team

Building email infrastructure for developers

Ready to start sending?

Get your API key and send your first email in under 5 minutes. No credit card required.