mirror of
https://github.com/xtr-dev/payload-mailing.git
synced 2025-12-10 16:23:23 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff94d72d49 | ||
| ddee7d5a76 | |||
|
|
0083e8e1fa | ||
| 63a7eef8d8 |
32
README.md
32
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
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@xtr-dev/payload-mailing",
|
||||
"version": "0.1.23",
|
||||
"version": "0.2.0",
|
||||
"description": "Template-based email system with scheduling and job processing for PayloadCMS",
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
|
||||
@@ -9,12 +9,6 @@ import { mailingJobs, scheduleEmailsJob } from './jobs/index.js'
|
||||
export const mailingPlugin = (pluginConfig: MailingPluginConfig) => (config: Config): Config => {
|
||||
const queueName = pluginConfig.queue || 'default'
|
||||
|
||||
// Validate queueName
|
||||
if (!queueName || typeof queueName !== 'string') {
|
||||
throw new Error('Invalid queue configuration: queue must be a non-empty string')
|
||||
}
|
||||
|
||||
|
||||
// Handle templates collection configuration
|
||||
const templatesConfig = pluginConfig.collections?.templates
|
||||
const templatesSlug = typeof templatesConfig === 'string' ? templatesConfig : 'email-templates'
|
||||
|
||||
@@ -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,35 +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 {
|
||||
console.log('[DEBUG] email: ', this.payload.email);
|
||||
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.')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,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,
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user