Skip to content

SendGrid Email Attachments: Send Files With Your Emails via API

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about SendGrid Email Attachments: Send Files With Your Emails via API. We cover key concepts, practical examples, and best practices to help you master this topic.

Send email attachments with SendGrid by base64-encoding file content and attaching it to the Mail object with appropriate content type, filename, and disposition headers.

What You'll Learn

How to attach files to SendGrid emails, encode binary content, set MIME types, use inline images in HTML, handle file size limits, and attach multiple files per email.

Why It Matters

Many transactional emails need attachments — PDF reports, invoices, receipts. SendGrid supports base64-encoded attachments up to 30MB. DodaTech sends threat report PDFs as attachments to enterprise customers.

Real-World Use

A weekly security report PDF is generated, base64-encoded, and attached to a personalized email. The recipient opens the email and downloads the report directly.

flowchart LR
    A["Generate PDF\nReport File"] --> B["Base64\nEncode"]
    B --> C["Create Attachment\nObject"]
    C --> D["Add to Mail\nObject"]
    D --> E["Send via\nSendGrid API"]
    E --> F["Recipient\nDownloads PDF"]
    style A fill:#dbeafe,stroke:#2563eb
    style C fill:#fef3c7,stroke:#d97706
    style F fill:#bbf7d0,stroke:#16a34a

Basic Attachment

import base64
import os
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail, Attachment, FileContent, FileName, FileType, Disposition

def send_email_with_attachment(to_email, subject, body, file_path):
    with open(file_path, "rb") as f:
        data = f.read()
        encoded = base64.b64encode(data).decode()

    attachment = Attachment(
        FileContent(encoded),
        FileName(os.path.basename(file_path)),
        FileType("application/pdf"),
        Disposition("attachment")
    )

    message = Mail(
        from_email="reports@dodatech.com",
        to_emails=to_email,
        subject=subject,
        html_content=body
    )
    message.attachment = attachment

    response = sg.send(message)
    print(f"Email with attachment sent: {response.status_code}")
    print(f"File: {os.path.basename(file_path)}")

send_email_with_attachment(
    to_email="alice@example.com",
    subject="Your Security Report - June 2026",
    body="<h1>Security Report</h1><p>Your monthly report is attached.</p>",
    file_path="/tmp/report_june_2026.pdf"
)
# Expected output: Email with attachment sent: 202
#                  File: report_june_2026.pdf

Multiple Attachments

def send_with_multiple_attachments(to_email, files):
    message = Mail(
        from_email="reports@dodatech.com",
        to_emails=to_email,
        subject="Monthly Security Package",
        html_content="<p>Your monthly reports are attached.</p>"
    )

    for file_path in files:
        with open(file_path, "rb") as f:
            data = f.read()
            encoded = base64.b64encode(data).decode()

        attachment = Attachment(
            FileContent(encoded),
            FileName(os.path.basename(file_path)),
            FileType("application/octet-stream"),
            Disposition("attachment")
        )
        message.attachment = attachment

    response = sg.send(message)
    print(f"Sent {len(files)} attachments: {response.status_code}")

send_with_multiple_attachments("bob@example.com", [
    "/tmp/report_june.pdf",
    "/tmp/threat_log.csv",
    "/tmp/summary.json"
])
# Expected output: Sent 3 attachments: 202

Inline Images

def send_with_inline_image(to_email, image_path, cid="header_logo"):
    with open(image_path, "rb") as f:
        data = f.read()
        encoded = base64.b64encode(data).decode()

    attachment = Attachment(
        FileContent(encoded),
        FileName("logo.png"),
        FileType("image/png"),
        Disposition("inline"),
        ContentId(cid)  # Content ID for inline reference
    )

    message = Mail(
        from_email="reports@dodatech.com",
        to_emails=to_email,
        subject="Security Report with Logo",
        html_content=f'<img src="cid:{cid}" alt="Logo" width="200"><h1>Your Report</h1>'
    )
    message.attachment = attachment

    response = sg.send(message)
    print(f"Inline image email sent: {response.status_code}")

send_with_inline_image("carol@example.com", "/tmp/logo.png")
# Expected output: Inline image email sent: 202

Common Mistakes

1. Forgetting to Base64 Encode

SendGrid requires base64-encoded binary data. Passing raw binary or a file path directly causes a 400 error.

2. Exceeding 30MB Total Attachment Size

The total attachment size limit is 30MB per email. For larger files, host externally and include a download link instead.

3. Wrong MIME Type

Incorrect content types may cause the file to render inline or not open. Use the correct MIME type: application/pdf, image/png, text/csv, etc.

4. Using Wrong Disposition

attachment triggers download dialog. inline displays within the email body. Using inline for PDFs makes them display in the browser, not download.

5. Not Closing Files Properly

Always open files with with open(...) as f: context manager to ensure files are closed after reading, preventing resource leaks.

Practice Questions

  1. How are file attachments encoded for SendGrid?
  2. What is the maximum attachment size per email?
  3. What is the difference between attachment and inline dispositions?
  4. How do you reference an inline image in HTML content?

Answers:

  1. Files are base64-encoded (binary to ASCII text) and included in the JSON payload as a string.
  2. 30MB total across all attachments per email. For larger files, use external hosting with a download link.
  3. attachment prompts the recipient to download the file. inline displays the file within the email body (used for images shown in the email).
  4. Set ContentId on the attachment and reference it in HTML as <img src="cid:content_id"> where content_id matches.

Challenge: Build a report delivery system: generate a PDF threat report, attach it to a personalized email with an inline logo image, handle the 30MB size limit by splitting large reports, and verify the PDF opens correctly after delivery.

FAQ

What file types can I attach?

Any file type is supported. Use the correct MIME type for proper handling (PDF: application/pdf, PNG: image/png, ZIP: application/zip).

Can recipients reply with attachments?

SendGrid's Inbound Parse webhook can receive email attachments. Configure the Parse Webhook to accept and process incoming emails with attachments.

Are attachments scanned for viruses?

SendGrid does not scan attachments. Ensure your application scans files for malware before attaching them to emails.

How does base64 encoding affect file size?

Base64 encoding increases file size by approximately 33%. A 10MB file becomes about 13.3MB encoded.

Can I attach files from a URL?

No, you must download the file to your server, encode it, and attach it. SendGrid doesn't fetch URLs for attachments.

Mini Project

Build an automated report delivery system: generate a sample PDF report using Python, base64-encode and attach to a SendGrid email, add an inline header image, include multiple attachments (PDF + CSV), and verify the email with all attachments arrives correctly.

What's Next

Email Categories — organize and track emails with custom categories.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro