Unsend
Unsend plugin for Medusa 2
Unsend plugin for MedusaJS v2
Installation
Run the following command to install the plugin with npm:
npm install --save @rokmohar/medusa-plugin-unsend
Or with yarn:
yarn add @rokmohar/medusa-plugin-unsend
⚠️ MedusaJS v2.4.0 or newer
This plugin is only for MedusaJS v2.4.0 or newer.
If you are using MedusaJS v2.3.1 or older, please use the older version of this plugin.
Configuration
Add the plugin to your file:
import { loadEnv, defineConfig } from '@medusajs/framework/utils'import { UNSEND_PROVIDER_PATH } from '@rokmohar/medusa-plugin-unsend'loadEnv(process.env.NODE_ENV || 'development', process.cwd())module.exports = defineConfig({// ... other configplugins: [// ... other plugins{resolve: '@rokmohar/medusa-plugin-unsend',options: {// Required optionsurl: process.env.UNSEND_URL ?? '',api_key: process.env.UNSEND_API_KEY ?? '',from: process.env.UNSEND_FROM ?? '',// Optional configurationtemplateDir: 'custom/templates/path', // Custom template directoryretry: {maxAttempts: 5, // Number of retry attempts for failed sendsdelay: 2000, // Delay between retries in milliseconds},rateLimit: {maxPerMinute: 30, // Maximum emails per minute},// Environment configurations based on NODE_ENVenvironment: {development: {// Development-specific overridesfrom: 'dev@example.com',rateLimit: {maxPerMinute: 25,},},staging: {// Staging-specific overridesfrom: 'stage@example.com',rateLimit: {maxPerMinute: 50,},},production: {// Production-specific overridesfrom: 'prod@example.com',rateLimit: {maxPerMinute: 100,},},},},},],modules: [// ... other modules{resolve: '@medusajs/medusa/notification',dependencies: ['unsend'],options: {providers: [// ... other providers{resolve: UNSEND_PROVIDER_PATH,id: 'unsend',options: {channels: ['email'],},},],},},],})
ENV variables
Add the environment variables to your and file:
# ... others varsUNSEND_URL=UNSEND_API_KEY=UNSEND_FROM=
If you want to use with the from this README, use the following values:
# ... others varsUNSEND_URL=http://localhost:3000UNSEND_API_KEY=test_123456789UNSEND_FROM=no-reply@example.org
Email Templates
The plugin automatically loads email templates from the directory in your project root (or a custom directory specified in the configuration). Each template consists of two files:
- A TSX file containing the React component
- An optional JSON file for template metadata
Template Structure
// src/templates/emails/ProductUpsert.tsximport React from 'react'const ProductUpsertEmail = (props: any) => {return (<div><h1>Product Updated</h1><p>Product ID: {props.productId}</p></div>)}// Set email subjectProductUpsertEmail.Subject = 'Products upserted'export default ProductUpsertEmail
The email subject is determined in the following order of precedence:
- provided in the call
- field in the template's metadata JSON file
- static property in the TSX file
- Kebab-case template name (derived from the filename)
For example, if you have a template named , the subject will fall back to if no other subject is specified.
// src/templates/emails/ProductUpsert.json{"version": "1.0.0","subject": "Product upsert","description": "Email template for product updates","tags": ["product", "update"],"category": "product-notifications"}
The template name will be derived from the filename (without the .tsx extension). For example, will be available as the template named .
Template Metadata
The JSON file is optional and can contain the following fields:
- : Template version (defaults to "1.0.0")
- : Template subject
- : Template description
- : Array of tags for categorizing templates
- : Template category
Email Subject Precedence
The email subject is determined in the following order of precedence:
- provided in the call
- field in the template's metadata JSON file
- static property in the TSX file
- Kebab-case template name (derived from the filename)
For example, if you have a template named , the subject will fall back to if no other subject is specified.
Features
- Environment-specific Configuration: Override settings for different environments (development, staging, production)
- Rate Limiting: Prevent overwhelming the email service with configurable limits
- Retry Mechanism: Automatic retries for failed email sends with exponential backoff
- Template Versioning: Track template versions and changes
- Template Metadata: Add descriptions, tags, and categories to templates
- Custom Template Directory: Configure the location of your email templates
Subscribers
You must add the following subscribers to the :
product-upsert.ts
import { SubscriberArgs, SubscriberConfig } from '@medusajs/framework'import { IProductModuleService } from '@medusajs/framework/types'import { Modules } from '@medusajs/framework/utils'import { ProductEvents, SearchUtils } from '@medusajs/utils'import { UnsendService } from '@rokmohar/medusa-plugin-unsend/core'export default async function productCreatedHandler({ event: { data }, container }: SubscriberArgs<{ id: string }>) {const productId = data.id// Make sure template is registered, before creating email notificationsconst unsendService: UnsendService = container.resolve('unsend')const notificationModuleService = container.resolve(Modules.NOTIFICATION)await notificationModuleService.createNotifications({to: 'first.last@example.org',channel: 'email',// Use name of the registered templatetemplate: 'product-upsert',// Set email subjectcontent: {subject: 'Product upserted',},})}export const config: SubscriberConfig = {event: [ProductEvents.PRODUCT_CREATED, ProductEvents.PRODUCT_UPDATED],}
docker-compose
You can add the following configuration for Unsend to your :
services:# ... other servicesunsend:image: 'unsend/unsend:latest'port:- '3000:3000'