SendGrid Email Attachments: Send Files With Your Emails via API
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
- How are file attachments encoded for SendGrid?
- What is the maximum attachment size per email?
- What is the difference between
attachmentandinlinedispositions? - How do you reference an inline image in HTML content?
Answers:
- Files are base64-encoded (binary to ASCII text) and included in the JSON payload as a string.
- 30MB total across all attachments per email. For larger files, use external hosting with a download link.
attachmentprompts the recipient to download the file.inlinedisplays the file within the email body (used for images shown in the email).- Set
ContentIdon the attachment and reference it in HTML as<img src="cid:content_id">wherecontent_idmatches.
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
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