Skip to content

Commit efa4afe

Browse files
chore(deps): bump nodemailer minimum version to 8.0.5 (#16664)
Supersedes #16501. Related: #16651. Bumps `nodemailer` to `^8.0.5` and `@types/nodemailer` to `^8.0.0` throughout the monorepo. The `nodemailer@7.0.12` package has known advisories that are fixed in >= 8.0.5. - GHSA-vvjj-xcjg-gr5g - GHSA-c7w3-x93f-qmm8 Note: `nodemailer` v8 widened the `Mail.Options['from']` type to also accept an array. This is considered a breaking change in Payload's `SendEmailOptions` type, if a project code relies on the previous shape. For backwards compatibility, we pin `SendEmailOptions['from']` back to v7's `string | Address` shape, then normalize this at runtime, so email adapters and consumer code stay source-compatible. --- - To see the specific tasks where the Asana app for GitHub is being used, see below: - https://app.asana.com/0/0/1214892618463672 --------- Co-authored-by: Andrea Barani <andrea.barani@vubai.com>
1 parent cf9252d commit efa4afe

8 files changed

Lines changed: 101 additions & 156 deletions

File tree

packages/email-nodemailer/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,10 @@
4242
"lint:fix": "eslint . --fix"
4343
},
4444
"dependencies": {
45-
"nodemailer": "7.0.12"
45+
"nodemailer": "^8.0.5"
4646
},
4747
"devDependencies": {
48-
"@types/nodemailer": "7.0.2",
48+
"@types/nodemailer": "^8.0.0",
4949
"payload": "workspace:*"
5050
},
5151
"peerDependencies": {

packages/payload-cloud/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,10 @@
4848
"@aws-sdk/lib-storage": "^3.614.0",
4949
"@payloadcms/email-nodemailer": "workspace:*",
5050
"amazon-cognito-identity-js": "^6.1.2",
51-
"nodemailer": "7.0.12"
51+
"nodemailer": "^8.0.5"
5252
},
5353
"devDependencies": {
54-
"@types/nodemailer": "7.0.2",
54+
"@types/nodemailer": "^8.0.0",
5555
"payload": "workspace:*"
5656
},
5757
"peerDependencies": {

packages/payload/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@
137137
"@payloadcms/eslint-config": "workspace:*",
138138
"@types/json-schema": "7.0.15",
139139
"@types/minimist": "1.2.2",
140-
"@types/nodemailer": "7.0.2",
140+
"@types/nodemailer": "^8.0.0",
141141
"@types/pluralize": "0.0.33",
142142
"@types/range-parser": "1.2.7",
143143
"@types/ws": "^8.5.10",
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import type { Address } from 'nodemailer/lib/mailer'
2+
3+
/**
4+
* @todo: Remove in v4.
5+
*
6+
* This is a runtime guard to handle the breaking change in nodemailer v8.
7+
*
8+
* The `from` property is intentionally narrowed back to nodemailer 7's shape.
9+
* Nodemailer v8 (security patch) widened it to also accept an array of addresses (breaking change).
10+
* For backwards compatibility, we normalize that from an array back to a single address at runtime.
11+
*/
12+
export function normalizeSendEmailOptions<T extends { from?: unknown }>(message: T): T {
13+
if (!Array.isArray(message.from)) {
14+
return message
15+
}
16+
17+
const first = (message.from as Array<Address | string>)[0]
18+
return {
19+
...message,
20+
from: typeof first === 'string' || (first && typeof first === 'object') ? first : undefined,
21+
} as { from?: Address | string } & T
22+
}

packages/payload/src/email/types.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { SendMailOptions as NodemailerSendMailOptions } from 'nodemailer'
2+
import type { Address } from 'nodemailer/lib/mailer'
23

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

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

910
/**
10-
* Options for sending an email. Allows access to the PayloadRequest object
11+
* Options for sending an email. Allows access to the PayloadRequest object.
12+
*
13+
* @todo: Remove in v4. See `normalizeSendEmailOptions` for details.
1114
*/
12-
export type SendEmailOptions = Prettify<NodemailerSendMailOptions>
15+
export type SendEmailOptions = Prettify<
16+
{
17+
from?: Address | string
18+
} & Omit<NodemailerSendMailOptions, 'from'>
19+
>
1320

1421
/**
1522
* Email adapter after it has been initialized. This is used internally by Payload.

packages/payload/src/index.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ import {
141141
type CountVersionsOptions,
142142
} from './collections/operations/local/countVersions.js'
143143
import { consoleEmailAdapter } from './email/consoleEmailAdapter.js'
144+
import { normalizeSendEmailOptions } from './email/normalizeSendEmailOptions.js'
144145
import { fieldAffectsData, type FlattenedBlock } from './fields/config/types.js'
145146
import { getJobsLocalAPI } from './queues/localAPI.js'
146147
import { _internal_jobSystemGlobals } from './queues/utilities/getCurrentDate.js'
@@ -953,7 +954,12 @@ export class BasePayload {
953954
}
954955
}
955956

956-
this.sendEmail = this.email['sendEmail']
957+
/**
958+
* @todo: Remove in v4.
959+
* See `normalizeSendEmailOptions` for details.
960+
*/
961+
const adapterSendEmail = this.email['sendEmail']
962+
this.sendEmail = (message) => adapterSendEmail(normalizeSendEmailOptions(message))
957963

958964
serverInitTelemetry(this)
959965

pnpm-lock.yaml

Lines changed: 57 additions & 147 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@
9999
"jwt-decode": "4.0.0",
100100
"mongoose": "8.15.1",
101101
"next": "16.2.6",
102-
"nodemailer": "8.0.4",
102+
"nodemailer": "^8.0.5",
103103
"object-to-formdata": "4.5.1",
104104
"payload": "workspace:*",
105105
"pg": "8.16.3",

0 commit comments

Comments
 (0)