mirror of
https://github.com/xtr-dev/payload-mailing.git
synced 2025-12-10 08:13:23 +00:00
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.
This commit is contained in:
32
README.md
32
README.md
@@ -28,26 +28,31 @@ npm install @xtr-dev/payload-mailing
|
|||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
### 1. Add the plugin to your Payload config
|
### 1. Configure email in your Payload config and add the plugin
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { buildConfig } from 'payload/config'
|
import { buildConfig } from 'payload/config'
|
||||||
import { mailingPlugin } from '@xtr-dev/payload-mailing'
|
import { mailingPlugin } from '@xtr-dev/payload-mailing'
|
||||||
|
import { nodemailerAdapter } from '@payloadcms/email-nodemailer'
|
||||||
|
|
||||||
export default buildConfig({
|
export default buildConfig({
|
||||||
// ... your config
|
// ... 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: [
|
plugins: [
|
||||||
mailingPlugin({
|
mailingPlugin({
|
||||||
defaultFrom: 'noreply@yoursite.com',
|
defaultFrom: 'noreply@yoursite.com',
|
||||||
transport: {
|
defaultFromName: 'Your Site Name',
|
||||||
host: 'smtp.gmail.com',
|
|
||||||
port: 587,
|
|
||||||
secure: false,
|
|
||||||
auth: {
|
|
||||||
user: process.env.EMAIL_USER,
|
|
||||||
pass: process.env.EMAIL_PASS,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
retryAttempts: 3,
|
retryAttempts: 3,
|
||||||
retryDelay: 300000, // 5 minutes
|
retryDelay: 300000, // 5 minutes
|
||||||
queue: 'email-queue', // optional
|
queue: 'email-queue', // optional
|
||||||
@@ -119,13 +124,6 @@ mailingPlugin({
|
|||||||
return yourCustomEngine.render(template, variables)
|
return yourCustomEngine.render(template, variables)
|
||||||
},
|
},
|
||||||
|
|
||||||
// Email transport
|
|
||||||
transport: {
|
|
||||||
host: 'smtp.gmail.com',
|
|
||||||
port: 587,
|
|
||||||
auth: { user: '...', pass: '...' }
|
|
||||||
},
|
|
||||||
|
|
||||||
// Collection names (optional)
|
// Collection names (optional)
|
||||||
collections: {
|
collections: {
|
||||||
templates: 'email-templates', // default
|
templates: 'email-templates', // default
|
||||||
|
|||||||
@@ -135,15 +135,6 @@ const buildConfigWithMemoryDB = async () => {
|
|||||||
mailingPlugin({
|
mailingPlugin({
|
||||||
defaultFrom: 'noreply@test.com',
|
defaultFrom: 'noreply@test.com',
|
||||||
initOrder: 'after',
|
initOrder: 'after',
|
||||||
transport: {
|
|
||||||
host: 'localhost',
|
|
||||||
port: 1025, // MailHog port for dev
|
|
||||||
secure: false,
|
|
||||||
auth: {
|
|
||||||
user: 'test',
|
|
||||||
pass: 'test',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
retryAttempts: 3,
|
retryAttempts: 3,
|
||||||
retryDelay: 60000, // 1 minute for dev
|
retryDelay: 60000, // 1 minute for dev
|
||||||
queue: 'email-queue',
|
queue: 'email-queue',
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@xtr-dev/payload-mailing",
|
"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",
|
"description": "Template-based email system with scheduling and job processing for PayloadCMS",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
import { Payload } from 'payload'
|
import { Payload } from 'payload'
|
||||||
import { Liquid } from 'liquidjs'
|
import { Liquid } from 'liquidjs'
|
||||||
import nodemailer, { Transporter } from 'nodemailer'
|
|
||||||
import {
|
import {
|
||||||
MailingPluginConfig,
|
MailingPluginConfig,
|
||||||
TemplateVariables,
|
TemplateVariables,
|
||||||
MailingService as IMailingService,
|
MailingService as IMailingService,
|
||||||
MailingTransportConfig,
|
|
||||||
BaseEmail, BaseEmailTemplate, BaseEmailDocument, BaseEmailTemplateDocument
|
BaseEmail, BaseEmailTemplate, BaseEmailDocument, BaseEmailTemplateDocument
|
||||||
} from '../types/index.js'
|
} from '../types/index.js'
|
||||||
import { serializeRichTextToHTML, serializeRichTextToText } from '../utils/richTextSerializer.js'
|
import { serializeRichTextToHTML, serializeRichTextToText } from '../utils/richTextSerializer.js'
|
||||||
@@ -13,11 +11,10 @@ import { serializeRichTextToHTML, serializeRichTextToText } from '../utils/richT
|
|||||||
export class MailingService implements IMailingService {
|
export class MailingService implements IMailingService {
|
||||||
public payload: Payload
|
public payload: Payload
|
||||||
private config: MailingPluginConfig
|
private config: MailingPluginConfig
|
||||||
private transporter!: Transporter | any
|
private emailAdapter: any
|
||||||
private templatesCollection: string
|
private templatesCollection: string
|
||||||
private emailsCollection: string
|
private emailsCollection: string
|
||||||
private liquid: Liquid | null | false = null
|
private liquid: Liquid | null | false = null
|
||||||
private transporterInitialized = false
|
|
||||||
|
|
||||||
constructor(payload: Payload, config: MailingPluginConfig) {
|
constructor(payload: Payload, config: MailingPluginConfig) {
|
||||||
this.payload = payload
|
this.payload = payload
|
||||||
@@ -29,34 +26,19 @@ export class MailingService implements IMailingService {
|
|||||||
const emailsConfig = config.collections?.emails
|
const emailsConfig = config.collections?.emails
|
||||||
this.emailsCollection = typeof emailsConfig === 'string' ? emailsConfig : 'emails'
|
this.emailsCollection = typeof emailsConfig === 'string' ? emailsConfig : 'emails'
|
||||||
|
|
||||||
this.initializeTransporter()
|
// 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.')
|
||||||
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')
|
|
||||||
}
|
}
|
||||||
|
this.emailAdapter = this.payload.email
|
||||||
this.transporterInitialized = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ensureInitialized(): void {
|
private ensureInitialized(): void {
|
||||||
if (!this.payload || !this.payload.db) {
|
if (!this.payload || !this.payload.db) {
|
||||||
throw new Error('MailingService payload not properly initialized')
|
throw new Error('MailingService payload not properly initialized')
|
||||||
}
|
}
|
||||||
if (!this.transporterInitialized) {
|
if (!this.emailAdapter) {
|
||||||
this.initializeTransporter()
|
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({
|
await this.payload.update({
|
||||||
collection: this.emailsCollection as any,
|
collection: this.emailsCollection as any,
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { Payload } from 'payload'
|
import { Payload } from 'payload'
|
||||||
import type { CollectionConfig, RichTextField } from 'payload'
|
import type { CollectionConfig, RichTextField } from 'payload'
|
||||||
import { Transporter } from 'nodemailer'
|
|
||||||
|
|
||||||
// JSON value type that matches Payload's JSON field type
|
// JSON value type that matches Payload's JSON field type
|
||||||
export type JSONValue = string | number | boolean | { [k: string]: unknown } | unknown[] | null | undefined
|
export type JSONValue = string | number | boolean | { [k: string]: unknown } | unknown[] | null | undefined
|
||||||
@@ -70,7 +69,6 @@ export interface MailingPluginConfig {
|
|||||||
}
|
}
|
||||||
defaultFrom?: string
|
defaultFrom?: string
|
||||||
defaultFromName?: string
|
defaultFromName?: string
|
||||||
transport?: Transporter | MailingTransportConfig
|
|
||||||
queue?: string
|
queue?: string
|
||||||
retryAttempts?: number
|
retryAttempts?: number
|
||||||
retryDelay?: number
|
retryDelay?: number
|
||||||
@@ -82,17 +80,6 @@ export interface MailingPluginConfig {
|
|||||||
initOrder?: 'before' | 'after'
|
initOrder?: 'before' | 'after'
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MailingTransportConfig {
|
|
||||||
host: string
|
|
||||||
port: number
|
|
||||||
secure?: boolean
|
|
||||||
auth?: {
|
|
||||||
user: string
|
|
||||||
pass: string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export interface QueuedEmail {
|
export interface QueuedEmail {
|
||||||
id: string
|
id: string
|
||||||
template?: string | null
|
template?: string | null
|
||||||
|
|||||||
Reference in New Issue
Block a user