Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/email-nodemailer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@
"lint:fix": "eslint . --fix"
},
"dependencies": {
"nodemailer": "7.0.12"
"nodemailer": "^8.0.5"
},
"devDependencies": {
"@types/nodemailer": "7.0.2",
"@types/nodemailer": "^8.0.0",
"payload": "workspace:*"
},
"peerDependencies": {
Expand Down
4 changes: 2 additions & 2 deletions packages/payload-cloud/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@
"@aws-sdk/lib-storage": "^3.614.0",
"@payloadcms/email-nodemailer": "workspace:*",
"amazon-cognito-identity-js": "^6.1.2",
"nodemailer": "7.0.12"
"nodemailer": "^8.0.5"
},
"devDependencies": {
"@types/nodemailer": "7.0.2",
"@types/nodemailer": "^8.0.0",
"payload": "workspace:*"
},
"peerDependencies": {
Expand Down
2 changes: 1 addition & 1 deletion packages/payload/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@
"@payloadcms/eslint-config": "workspace:*",
"@types/json-schema": "7.0.15",
"@types/minimist": "1.2.2",
"@types/nodemailer": "7.0.2",
"@types/nodemailer": "^8.0.0",
"@types/pluralize": "0.0.33",
"@types/range-parser": "1.2.7",
"@types/ws": "^8.5.10",
Expand Down
22 changes: 22 additions & 0 deletions packages/payload/src/email/normalizeSendEmailOptions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { Address } from 'nodemailer/lib/mailer'

/**
* @todo: Remove in v4.
*
* This is a runtime guard to handle the breaking change in nodemailer v8.
*
* The `from` property is intentionally narrowed back to nodemailer 7's shape.
* Nodemailer v8 (security patch) widened it to also accept an array of addresses (breaking change).
* For backwards compatibility, we normalize that from an array back to a single address at runtime.
*/
export function normalizeSendEmailOptions<T extends { from?: unknown }>(message: T): T {
if (!Array.isArray(message.from)) {
return message
}

const first = (message.from as Array<Address | string>)[0]
return {
...message,
from: typeof first === 'string' || (first && typeof first === 'object') ? first : undefined,
} as { from?: Address | string } & T
}
11 changes: 9 additions & 2 deletions packages/payload/src/email/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { SendMailOptions as NodemailerSendMailOptions } from 'nodemailer'
import type { Address } from 'nodemailer/lib/mailer'

import type { Payload } from '../types/index.js'

Expand All @@ -7,9 +8,15 @@ type Prettify<T> = {
} & NonNullable<unknown>

/**
* Options for sending an email. Allows access to the PayloadRequest object
* Options for sending an email. Allows access to the PayloadRequest object.
*
* @todo: Remove in v4. See `normalizeSendEmailOptions` for details.
*/
export type SendEmailOptions = Prettify<NodemailerSendMailOptions>
export type SendEmailOptions = Prettify<
{
from?: Address | string
} & Omit<NodemailerSendMailOptions, 'from'>
>

/**
* Email adapter after it has been initialized. This is used internally by Payload.
Expand Down
8 changes: 7 additions & 1 deletion packages/payload/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ import {
type CountVersionsOptions,
} from './collections/operations/local/countVersions.js'
import { consoleEmailAdapter } from './email/consoleEmailAdapter.js'
import { normalizeSendEmailOptions } from './email/normalizeSendEmailOptions.js'
import { fieldAffectsData, type FlattenedBlock } from './fields/config/types.js'
import { getJobsLocalAPI } from './queues/localAPI.js'
import { _internal_jobSystemGlobals } from './queues/utilities/getCurrentDate.js'
Expand Down Expand Up @@ -953,7 +954,12 @@ export class BasePayload {
}
}

this.sendEmail = this.email['sendEmail']
/**
* @todo: Remove in v4.
* See `normalizeSendEmailOptions` for details.
*/
const adapterSendEmail = this.email['sendEmail']
this.sendEmail = (message) => adapterSendEmail(normalizeSendEmailOptions(message))

serverInitTelemetry(this)

Expand Down
204 changes: 57 additions & 147 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@
"jwt-decode": "4.0.0",
"mongoose": "8.15.1",
"next": "16.2.6",
"nodemailer": "8.0.4",
"nodemailer": "^8.0.5",
"object-to-formdata": "4.5.1",
"payload": "workspace:*",
"pg": "8.16.3",
Expand Down
Loading