2026-07-15

How to attach file to an email with nodemailer

Stefan Bogdanescu

Stefan Bogdanescu

Founder & Senior Architect

How to attach file to an email with nodemailer

Mastering File Attachments with Nodemailer: A Complete Guide

As developers, sending emails is a fundamental task for almost any application. While basic text emails are straightforward, attaching files—whether PDFs, images, or documents—adds significant value to your communication. If you are using Nodemailer in Node.js and find yourself struggling to attach files, you are not alone. The process involves more than just setting the text and html fields; it requires interfacing with the Node.js File System (fs) module to read the file content and structure it correctly for the email server.

This guide will walk you through the exact method to successfully attach files to emails using Nodemailer, ensuring your communication is robust and professional.

The Core Concept: Reading Files into Buffers

Nodemailer does not natively handle file uploads directly from a local path. Instead, you must manually read the file contents from the disk and package them into a format that the SMTP server understands. The standard way to achieve this in Node.js is by using the built-in fs (File System) module.

When attaching files, Nodemailer expects the file content as a Buffer or a stream, along with the desired filename and MIME type for proper rendering on the recipient's end.

Step-by-Step Implementation

To attach a file, you need three main components:

  1. The file path to the file you want to send.
  2. The content of that file (read using fs).
  3. The configuration object passed to sendMail(), specifically the attachments array.

Here is a complete example demonstrating how to attach a local file:

const nodemailer = require('nodemailer');
const fs = require('fs'); // Import the File System module

// --- Configuration ---
const filePath = './my_document.pdf'; // Replace with the actual path to your file
const attachmentName = 'Report_Q3_2024.pdf';

// 1. Create the transporter (Setup remains the same)
const smtpTransport = nodemailer.createTransport({
    service: "gmail",
    auth: {
        user: "example@gmail.com",
        pass: "pass"
    }
});

async function sendEmailWithAttachment() {
    try {
        // 2. Read the file content into a Buffer
        const attachmentBuffer = fs.readFileSync(filePath);

        // 3. Define the attachment details
        const attachment = {
            filename: attachmentName,
            content: attachmentBuffer.toString('base64'), // Encoding is crucial for MIME attachments
            contentType: 'application/pdf' // Set the correct MIME type
        };

        // 4. Define the mail options, including the attachments array
        const mailOptions = {
            from: 'example@gmail.com',
            to:  'recipient@example.com',
            subject: 'Document Attached: Q3 Report',
            text: 'Please find the attached document.',
            html: '<p>Hello,</p><p>Attached is your requested file.</p>',
            attachments: [attachment] // <-- This is where the attachment is added
        };

        // 5. Send the mail
        const info = await smtpTransport.sendMail(mailOptions);
        console.log('Email sent successfully: ' + info.messageId);

    } catch (error) {
        console.error('Error sending email or reading file:', error);
    }
}

sendEmailWithAttachment();

Best Practices and Security Considerations

When dealing with file attachments, security and performance are paramount.

1. Use Streams for Large Files

The example above uses fs.readFileSync(), which reads the entire file into memory at once. For very large files (e.g., multi-megabyte documents), this can consume excessive memory. A more scalable approach is to use streams (fs.createReadStream). This allows you to pipe the file data directly to your Nodemailer operation, keeping memory usage low and efficient.

2. Correct MIME Types

Always ensure you set the correct contentType. If you attach a JPEG image, the content type should be image/jpeg; for a PDF, it should be application/pdf. Incorrect MIME types can lead to clients being unable to display the attachment correctly.

3. Backend Architecture (Laravel Context)

When building complex applications, especially those involving file storage and delivery, leveraging robust backend services is essential. Frameworks like Laravel excel at managing file uploads, storage, and permissions cleanly. When integrating Node.js services with such systems, ensure your communication protocol handles the data exchange reliably. For instance, understanding how a framework manages file persistence can inform how you structure the file reading process in your Node service.

Conclusion

Attaching files to emails with Nodemailer is entirely achievable by bridging the gap between the local file system and the email transport layer using Node.js's fs module. By correctly reading the file content, encoding it appropriately (using Base64 for MIME attachments), and structuring the message options with an attachments array, you can reliably deliver rich communication. Always prioritize using streams for large files and double-check your MIME types to ensure a seamless experience for your recipients.

Tags:

Enhance your marketing setup with your own email marketing platform.

Join the growing number of SaaS platforms using Laravel Mail to offer email marketing solutions to their customers.