How Base64 Encodes Email Attachments in MIME
Ever wondered how a PDF or image survives being sent through email — a protocol built in the 1980s for plain 7-bit ASCII text? The answer is MIME, and inside MIME, the answer is almost always Base64. This article breaks down exactly how it works with a real, simplified raw email example.
Why email needs an encoding layer at all
SMTP, the protocol that transports email, was designed around 7-bit ASCII text. Many mail relays and servers along the way are still only guaranteed to pass through printable ASCII safely. Binary files — images, PDFs, ZIPs — contain arbitrary byte values (0–255), which risk corruption or truncation if sent raw. MIME solves this by wrapping binary content in Base64 text before it enters the SMTP pipeline.
MIME multipart structure
A MIME email with an attachment is a multipart/mixed message: multiple parts separated by a unique boundary string, each with its own headers describing its content type and encoding.
From: sender@example.com To: receiver@example.com Subject: Invoice attached MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="BOUNDARY123" --BOUNDARY123 Content-Type: text/plain; charset="utf-8" Hi, please find the invoice attached. --BOUNDARY123 Content-Type: application/pdf; name="invoice.pdf" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="invoice.pdf" JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PC9UeXBlL0NhdGFsb2cvUGFn ZXMgMiAwIFI+PgplbmRvYmoKMiAwIG9iago8PC9UeXBlL1BhZ2VzL0tp ZHNbMyAwIFJdL0NvdW50IDE+PgplbmRvYmoK... --BOUNDARY123--
The two lines that matter most: Content-Type: application/pdf tells the mail client what kind of file this is, and Content-Transfer-Encoding: base64 tells it the body between the boundaries is Base64 text that must be decoded back to binary before saving as a file.
Building a MIME attachment in Node.js
import fs from 'fs';
function buildMimeMessage({ to, from, subject, bodyText, attachmentPath }) {
const boundary = 'BOUNDARY_' + Date.now();
const fileBuffer = fs.readFileSync(attachmentPath);
const fileBase64 = fileBuffer.toString('base64');
const fileName = attachmentPath.split('/').pop();
// MIME requires each Base64 line to be wrapped, traditionally at 76 chars
const wrapped = fileBase64.match(/.{1,76}/g).join('\r\n');
return [
`From: ${from}`,
`To: ${to}`,
`Subject: ${subject}`,
'MIME-Version: 1.0',
`Content-Type: multipart/mixed; boundary="${boundary}"`,
'',
`--${boundary}`,
'Content-Type: text/plain; charset="utf-8"',
'',
bodyText,
'',
`--${boundary}`,
`Content-Type: application/octet-stream; name="${fileName}"`,
'Content-Transfer-Encoding: base64',
`Content-Disposition: attachment; filename="${fileName}"`,
'',
wrapped,
'',
`--${boundary}--`,
].join('\r\n');
}In practice: use a mail library, not raw MIME
You rarely build raw MIME by hand. Libraries like Nodemailer handle Base64 encoding, boundary generation, and line-wrapping for you — but knowing what happens underneath helps when debugging a broken attachment or an email that shows garbled text.
import nodemailer from 'nodemailer';
const transporter = nodemailer.createTransport({ /* SMTP config */ });
await transporter.sendMail({
from: 'sender@example.com',
to: 'receiver@example.com',
subject: 'Invoice attached',
text: 'Hi, please find the invoice attached.',
attachments: [
{ filename: 'invoice.pdf', path: './invoice.pdf' },
// Nodemailer Base64-encodes this automatically inside the MIME message
],
});Practical implications
- Attachments make emails ~33% larger than the raw file size — factor this into mailbox storage and attachment size limits (commonly 20–25 MB per provider).
- Garbled or unreadable attachments are often a wrapping/line-length issue in the Base64 body, or a missing
Content-Transfer-Encodingheader. - Inline images in HTML emails use the same mechanism via
Content-IDreferences andcid:URLs pointing to a Base64-encoded MIME part.
Frequently Asked Questions
Email was originally designed to carry only 7-bit ASCII text (SMTP). Binary files like images or PDFs contain bytes outside that range, so MIME encodes them as Base64 text so they can travel safely through mail servers built for plain text.
MIME (Multipurpose Internet Mail Extensions) is the standard that defines how email messages carry multiple parts — text body, HTML body, and attachments. MIME uses Content-Transfer-Encoding: base64 to mark a part as Base64-encoded binary data.
Yes, Base64 adds about 33% to the attachment size. A 3 MB PDF becomes roughly 4 MB once Base64-encoded inside the MIME message, which is why large attachments take noticeably longer to send and receive than their original file size suggests.