Skip to content

Commit 61547f9

Browse files
authored
docs: adds examples for sending email attachments (#14665)
Fixes #12813
1 parent 276685d commit 61547f9

File tree

1 file changed

+152
-0
lines changed

1 file changed

+152
-0
lines changed

docs/email/overview.mdx

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,158 @@ const email = await payload.sendEmail({
158158
})
159159
```
160160

161+
## Sending email with attachments
162+
163+
**Nodemailer adapter (SMTP/SendGrid/etc.)**
164+
165+
Works with `@payloadcms/email-nodemailer` and any Nodemailer transport.
166+
167+
```ts
168+
await payload.sendEmail({
169+
to: 'user@example.com',
170+
subject: 'Your report',
171+
html: '<p>See attached.</p>',
172+
attachments: [
173+
// From a file path (local disk, mounted volume, etc.)
174+
{
175+
filename: 'invoice.pdf',
176+
path: '/var/data/invoice.pdf',
177+
contentType: 'application/pdf',
178+
},
179+
// From a Buffer you generated at runtime
180+
{
181+
filename: 'report.csv',
182+
content: Buffer.from('col1,col2\nA,B\n'),
183+
contentType: 'text/csv',
184+
},
185+
],
186+
})
187+
```
188+
189+
Anything supported by Nodemailer’s attachments—streams, Buffers, URLs, content IDs for inline images (cid), etc.—will work here.
190+
191+
### Resend adapter
192+
193+
Works with @payloadcms/email-resend.
194+
195+
For attachments from remote URLs
196+
197+
```ts
198+
await payload.sendEmail({
199+
to: 'user@example.com',
200+
subject: 'Your invoice',
201+
html: '<p>Thanks! Invoice attached.</p>',
202+
attachments: [
203+
{
204+
// Resend will fetch this URL
205+
path: 'https://example.com/invoices/1234.pdf',
206+
filename: 'invoice-1234.pdf',
207+
},
208+
],
209+
})
210+
```
211+
212+
For a local file
213+
214+
```ts
215+
import { readFile } from 'node:fs/promises'
216+
const pdf = await readFile('/var/data/invoice.pdf')
217+
await payload.sendEmail({
218+
to: 'user@example.com',
219+
subject: 'Your invoice',
220+
html: '<p>Thanks! Invoice attached.</p>',
221+
attachments: [
222+
{
223+
filename: 'invoice.pdf',
224+
// Resend expects Base64 here
225+
content: pdf.toString('base64'),
226+
},
227+
],
228+
})
229+
```
230+
231+
## Attaching files from Payload media collections
232+
233+
If you store files in a Payload collection with `upload: true`, you can attach them to emails by fetching the document and using its file data.
234+
235+
**Example: Attaching a file from a Media collection**
236+
237+
```ts
238+
const mediaDoc = await payload.findByID({
239+
collection: 'media',
240+
id: 'your-file-id',
241+
})
242+
243+
// For local storage adapter
244+
await payload.sendEmail({
245+
to: 'user@example.com',
246+
subject: 'Your document',
247+
html: '<p>Attached is the document you requested.</p>',
248+
attachments: [
249+
{
250+
filename: mediaDoc.filename,
251+
path: mediaDoc.url, // Local file path when using local storage
252+
contentType: mediaDoc.mimeType,
253+
},
254+
],
255+
})
256+
257+
// For cloud storage (S3, Azure, GCS, etc.)
258+
const response = await fetch(mediaDoc.url)
259+
const buffer = Buffer.from(await response.arrayBuffer())
260+
261+
await payload.sendEmail({
262+
to: 'user@example.com',
263+
subject: 'Your document',
264+
html: '<p>Attached is the document you requested.</p>',
265+
attachments: [
266+
{
267+
filename: mediaDoc.filename,
268+
content: buffer,
269+
contentType: mediaDoc.mimeType,
270+
},
271+
],
272+
})
273+
```
274+
275+
### With Resend adapter:
276+
277+
```ts
278+
const mediaDoc = await payload.findByID({
279+
collection: 'media',
280+
id: 'your-file-id',
281+
})
282+
283+
// If using cloud storage, Resend can fetch from the URL directly
284+
await payload.sendEmail({
285+
to: 'user@example.com',
286+
subject: 'Your document',
287+
html: '<p>Attached is the document you requested.</p>',
288+
attachments: [
289+
{
290+
filename: mediaDoc.filename,
291+
path: mediaDoc.url, // Resend will fetch from this URL
292+
},
293+
],
294+
})
295+
296+
// For local storage, read the file and convert to Base64
297+
import { readFile } from 'node:fs/promises'
298+
const fileBuffer = await readFile(mediaDoc.url)
299+
300+
await payload.sendEmail({
301+
to: 'user@example.com',
302+
subject: 'Your document',
303+
html: '<p>Attached is the document you requested.</p>',
304+
attachments: [
305+
{
306+
filename: mediaDoc.filename,
307+
content: fileBuffer.toString('base64'),
308+
},
309+
],
310+
})
311+
```
312+
161313
## Using multiple mail providers
162314

163315
Payload supports the use of a single transporter of email, but there is nothing stopping you from having more. Consider a use case where sending bulk email is handled differently than transactional email and could be done using a [hook](/docs/hooks/overview).

0 commit comments

Comments
 (0)