From ddee7d5a764f2cf4106d3942e8f77d8c374615bc Mon Sep 17 00:00:00 2001 From: Bas van den Aakster Date: Sun, 14 Sep 2025 16:57:30 +0200 Subject: [PATCH] BREAKING CHANGE: Remove custom transport support, use Payload's email config - Removed custom transport configuration from plugin - Plugin now requires Payload email to be configured - Simplified setup by relying on Payload's email adapter - Updated README with new configuration requirements - Bump version to 0.2.0 (breaking change) Users must now configure email in their Payload config using an email adapter like @payloadcms/email-nodemailer instead of configuring transport in the plugin. --- README.md | 32 +++++++++++++++---------------- dev/payload.config.ts | 9 --------- package.json | 2 +- src/services/MailingService.ts | 35 +++++++++------------------------- src/types/index.ts | 13 ------------- 5 files changed, 25 insertions(+), 66 deletions(-) diff --git a/README.md b/README.md index 9540532..b8fd70a 100644 --- a/README.md +++ b/README.md @@ -28,26 +28,31 @@ npm install @xtr-dev/payload-mailing ## Quick Start -### 1. Add the plugin to your Payload config +### 1. Configure email in your Payload config and add the plugin ```typescript import { buildConfig } from 'payload/config' import { mailingPlugin } from '@xtr-dev/payload-mailing' +import { nodemailerAdapter } from '@payloadcms/email-nodemailer' export default buildConfig({ // ... your config + email: nodemailerAdapter({ + defaultFromAddress: 'noreply@yoursite.com', + defaultFromName: 'Your Site', + transport: { + host: 'smtp.gmail.com', + port: 587, + auth: { + user: process.env.EMAIL_USER, + pass: process.env.EMAIL_PASS, + }, + }, + }), plugins: [ mailingPlugin({ defaultFrom: 'noreply@yoursite.com', - transport: { - host: 'smtp.gmail.com', - port: 587, - secure: false, - auth: { - user: process.env.EMAIL_USER, - pass: process.env.EMAIL_PASS, - }, - }, + defaultFromName: 'Your Site Name', retryAttempts: 3, retryDelay: 300000, // 5 minutes queue: 'email-queue', // optional @@ -119,13 +124,6 @@ mailingPlugin({ return yourCustomEngine.render(template, variables) }, - // Email transport - transport: { - host: 'smtp.gmail.com', - port: 587, - auth: { user: '...', pass: '...' } - }, - // Collection names (optional) collections: { templates: 'email-templates', // default diff --git a/dev/payload.config.ts b/dev/payload.config.ts index aa61182..c9e94ea 100644 --- a/dev/payload.config.ts +++ b/dev/payload.config.ts @@ -135,15 +135,6 @@ const buildConfigWithMemoryDB = async () => { mailingPlugin({ defaultFrom: 'noreply@test.com', initOrder: 'after', - transport: { - host: 'localhost', - port: 1025, // MailHog port for dev - secure: false, - auth: { - user: 'test', - pass: 'test', - }, - }, retryAttempts: 3, retryDelay: 60000, // 1 minute for dev queue: 'email-queue', diff --git a/package.json b/package.json index db40141..6059eb1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@xtr-dev/payload-mailing", - "version": "0.1.24", + "version": "0.2.0", "description": "Template-based email system with scheduling and job processing for PayloadCMS", "type": "module", "main": "dist/index.js", diff --git a/src/services/MailingService.ts b/src/services/MailingService.ts index e28508d..d1860fb 100644 --- a/src/services/MailingService.ts +++ b/src/services/MailingService.ts @@ -1,11 +1,9 @@ import { Payload } from 'payload' import { Liquid } from 'liquidjs' -import nodemailer, { Transporter } from 'nodemailer' import { MailingPluginConfig, TemplateVariables, MailingService as IMailingService, - MailingTransportConfig, BaseEmail, BaseEmailTemplate, BaseEmailDocument, BaseEmailTemplateDocument } from '../types/index.js' import { serializeRichTextToHTML, serializeRichTextToText } from '../utils/richTextSerializer.js' @@ -13,11 +11,10 @@ import { serializeRichTextToHTML, serializeRichTextToText } from '../utils/richT export class MailingService implements IMailingService { public payload: Payload private config: MailingPluginConfig - private transporter!: Transporter | any + private emailAdapter: any private templatesCollection: string private emailsCollection: string private liquid: Liquid | null | false = null - private transporterInitialized = false constructor(payload: Payload, config: MailingPluginConfig) { this.payload = payload @@ -29,34 +26,19 @@ export class MailingService implements IMailingService { const emailsConfig = config.collections?.emails this.emailsCollection = typeof emailsConfig === 'string' ? emailsConfig : 'emails' - this.initializeTransporter() - } - - private initializeTransporter(): void { - if (this.transporterInitialized) return - - if (this.config.transport) { - if ('sendMail' in this.config.transport) { - this.transporter = this.config.transport - } else { - this.transporter = nodemailer.createTransport(this.config.transport as MailingTransportConfig) - } - } else if (this.payload.email && 'sendMail' in this.payload.email) { - // Use Payload's configured mailer (cast to any to handle different adapter types) - this.transporter = this.payload.email as any - } else { - throw new Error('Email transport configuration is required either in plugin config or Payload config') + // Use Payload's configured email adapter + if (!this.payload.email) { + throw new Error('Payload email configuration is required. Please configure email in your Payload config.') } - - this.transporterInitialized = true + this.emailAdapter = this.payload.email } private ensureInitialized(): void { if (!this.payload || !this.payload.db) { throw new Error('MailingService payload not properly initialized') } - if (!this.transporterInitialized) { - this.initializeTransporter() + if (!this.emailAdapter) { + throw new Error('Email adapter not configured. Please ensure Payload has email configured.') } } @@ -302,7 +284,8 @@ export class MailingService implements IMailingService { } } - await this.transporter.sendMail(mailOptions) + // Send email using Payload's email adapter + await this.emailAdapter.sendEmail(mailOptions) await this.payload.update({ collection: this.emailsCollection as any, diff --git a/src/types/index.ts b/src/types/index.ts index 8944721..b545996 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,6 +1,5 @@ import { Payload } from 'payload' import type { CollectionConfig, RichTextField } from 'payload' -import { Transporter } from 'nodemailer' // JSON value type that matches Payload's JSON field type export type JSONValue = string | number | boolean | { [k: string]: unknown } | unknown[] | null | undefined @@ -70,7 +69,6 @@ export interface MailingPluginConfig { } defaultFrom?: string defaultFromName?: string - transport?: Transporter | MailingTransportConfig queue?: string retryAttempts?: number retryDelay?: number @@ -82,17 +80,6 @@ export interface MailingPluginConfig { initOrder?: 'before' | 'after' } -export interface MailingTransportConfig { - host: string - port: number - secure?: boolean - auth?: { - user: string - pass: string - } -} - - export interface QueuedEmail { id: string template?: string | null