How to Add Attachments to Mailto Links (The Truth + Workarounds)
TL;DR: Mailto links cannot directly attach files due to security restrictions. This guide explains why, explores attempted workarounds, and provides 5 legitimate alternatives that actually work.
The Hard Truth: Native Attachments Are Impossible
If you’re searching for “how to add attachments to mailto links,” we have bad news and good news.
Bad news: The mailto URI scheme, as defined in RFC 6068, does not support file attachments. This is intentional, not a bug.
Good news: There are several proven workarounds that achieve the same goal safely and reliably.
Why mailto: Can’t Attach Files (The Technical Explanation)
Security by Design
The mailto protocol was designed in 1998 (updated in 2010) to be stateless and URL-based. URLs can only contain:
- Text characters
- Encoded parameters
- Email addresses
URLs cannot contain:
- Binary file data
- File paths from user’s computer
- References to local files
The Security Problem
Imagine if mailto could attach files:
<!-- Hypothetical DANGEROUS syntax (doesn't actually work) -->
<a href="mailto:[email protected]?attach=/etc/passwd">
Click for free gift!
</a>
This would allow any website to:
- Read files from your computer
- Send them to arbitrary email addresses
- Exfiltrate sensitive data without permission
This is why W3C HTML specifications explicitly forbid file attachment parameters.
The attachment Parameter Myth
You might have seen code like this:
<!-- ❌ DOESN'T WORK -->
<a href="mailto:[email protected]?attachment=/path/to/file.pdf">
Email with attachment
</a>
This does nothing. Modern email clients ignore the attachment parameter entirely.
What Email Clients Actually Support
According to RFC 6068 Section 2, only these parameters are valid:
| Parameter | Purpose | Example |
|---|---|---|
to | Recipients | [email protected],[email protected] |
cc | Carbon copy | [email protected] |
bcc | Blind carbon copy | [email protected] |
subject | Email subject | subject=Hello%20World |
body | Email body text | body=Message%20here |
No attachment, file, or attach parameter exists.
Historical Attempts (And Why They Failed)
Attempt #1: The body Embed Hack
Theory: Embed file content in the body using base64 encoding.
<a href="mailto:[email protected]?body=--BEGIN-FILE--
JVBERi0xLjQKJeLjz9MKNiAwIG9iago8PC9UeXBlL0NhdGFsb2cvUGFnZXM...
--END-FILE--">
Why it failed:
- Body has character limits (2000-5000 depending on client)
- Binary data breaks email formatting
- No way to specify file type or name
- Email clients interpret as text, not attachment
Attempt #2: MAPI Protocol (Windows Only)
Theory: Use Windows MAPI (Messaging Application Programming Interface):
<a href="mapi:[email protected]?attachment=C:\file.pdf">
Why it failed:
- Only works in Outlook on Windows
- Requires local file path (security risk!)
- Blocked by modern browsers
- Doesn’t work on mobile/Mac/Linux
Status: Deprecated since Internet Explorer 11
Attempt #3: Data URI Scheme
Theory: Inline the file as a data URI:
<a href="mailto:[email protected]?body=<a href='data:application/pdf;base64,...'>File</a>">
Why it failed:
- HTML not rendered in mailto body
- Even if it was, clicking link in email wouldn’t work
- Data URIs for files are blocked in email for security
5 Working Alternatives to Mailto Attachments
Since native attachment support doesn’t exist, here are battle-tested workarounds used by millions of websites:
Alternative #1: Cloud Storage Links (Most Popular)
How it works: Upload file to cloud storage, include download link in email.
Services:
- Google Drive (15 GB free)
- Dropbox (2 GB free)
- WeTransfer (2 GB, temporary)
- SendGrid (email-specific)
Implementation:
<!-- User uploads file first, then clicks mailto -->
<input type="file" id="file-upload" />
<button onclick="uploadAndEmail()">Email with Attachment</button>
<script>
async function uploadAndEmail() {
const file = document.getElementById('file-upload').files[0];
// Upload to your cloud storage
const downloadUrl = await uploadToServer(file);
// Create mailto with link in body
const body = encodeURIComponent(
`Please download the attached file:\n\n${downloadUrl}`
);
window.location.href = `mailto:[email protected]?body=${body}`;
}
async function uploadToServer(file) {
const formData = new FormData();
formData.append('file', file);
const response = await fetch('/api/upload', {
method: 'POST',
body: formData
});
const data = await response.json();
return data.url; // Returns: https://yourdomain.com/files/abc123.pdf
}
</script>
Pros:
- ✅ Works with all email clients
- ✅ No file size limits (cloud storage dependent)
- ✅ Recipient doesn’t need special software
- ✅ Files can be password-protected
Cons:
- ❌ Requires server-side code
- ❌ Storage costs for large files
- ❌ Link expiration concerns
Best for: Business communications, large files, permanent sharing
Alternative #2: Mailto Body Template with Instructions
How it works: Pre-fill message asking user to attach manually.
<a href="mailto:[email protected]?subject=Job%20Application&body=Dear%20Hiring%20Team%2C%0A%0APlease%20find%20my%20resume%20attached.%0A%0A%5BAttach%20your%20resume%20before%20sending%5D%0A%0AName%3A%20%0APhone%3A%20">
Apply via Email
</a>
When clicked, this opens an email with:
Dear Hiring Team,
Please find my resume attached.
[Attach your resume before sending]
Name:
Phone:
Pros:
- ✅ Zero development required
- ✅ Works everywhere
- ✅ User retains full control
Cons:
- ❌ Relies on user to remember
- ❌ Easy to forget attachment
- ❌ Looks unprofessional
Best for: Personal sites, portfolios, simple contact scenarios
Pro tip: Our mailto generator can create these pre-filled templates in seconds.
Alternative #3: Contact Form with File Upload
How it works: Replace mailto with a proper form.
<form action="/api/contact" method="POST" enctype="multipart/form-data">
<input type="email" name="email" required />
<input type="file" name="attachment" accept=".pdf,.doc,.docx" />
<textarea name="message" required></textarea>
<button type="submit">Send Message</button>
</form>
Backend (Node.js example):
import express from 'express';
import multer from 'multer';
import nodemailer from 'nodemailer';
const upload = multer({ dest: 'uploads/' });
app.post('/api/contact', upload.single('attachment'), async (req, res) => {
const transporter = nodemailer.createTransport({ /* SMTP config */ });
await transporter.sendMail({
from: req.body.email,
to: '[email protected]',
subject: 'Contact Form Submission',
text: req.body.message,
attachments: [
{
filename: req.file.originalname,
path: req.file.path
}
]
});
res.json({ success: true });
});
Pros:
- ✅ Full control over attachments
- ✅ Can enforce file type/size limits
- ✅ Integrates with CRM/databases
- ✅ Better spam protection
Cons:
- ❌ Requires backend development
- ❌ More complex than mailto
- ❌ Ongoing maintenance
Best for: Job applications, support tickets, any scenario requiring attachments
Learn more: When to use forms vs mailto links
Alternative #4: Hybrid Approach (Mailto + Upload Link)
How it works: Provide both options.
<div class="contact-options">
<!-- Primary: Upload portal -->
<a href="/upload" class="btn-primary">
📎 Send Secure File
</a>
<!-- Alternative: Simple mailto -->
<a href="mailto:[email protected]" class="btn-secondary">
📧 Email Without Attachment
</a>
</div>
Pros:
- ✅ Accommodates all users
- ✅ Secure file handling option
- ✅ Fallback for simple inquiries
Cons:
- ❌ Requires maintaining both systems
Best for: Websites with mixed use cases
Alternative #5: QR Code with Embedded Instructions
How it works: Generate QR code containing mailto + attachment instructions.
// Generate QR code for mailto with reminder
const mailtoLink = 'mailto:[email protected]?subject=Application&body=Please%20attach%20resume';
const qrCode = generateQRCode(mailtoLink);
Example QR code mailto:
mailto:[email protected]
?subject=Job%20Application
&body=Remember%20to%20attach%3A%0A-%20Resume%20(PDF)%0A-%20Cover%20letter%0A-%20Portfolio%20link
Pros:
- ✅ Great for printed materials (business cards, posters)
- ✅ Mobile-friendly
- ✅ No server required
Cons:
- ❌ Still requires manual attachment
Best for: Offline-to-online conversion, events, physical marketing
Technical Deep Dive: Why Browsers Block File Access
Modern browsers implement the Same-Origin Policy which prevents:
// ❌ This is BLOCKED for security
const userFile = new File('/Users/john/Documents/secret.pdf');
sendEmail(userFile); // Not allowed!
// ✅ This is ALLOWED (user explicitly selects)
<input type="file" onchange="handleFile(event)">
Why? Without this protection:
- Malicious sites could read your filesystem
- Emails could exfiltrate data
- Attachments could contain malware
The File API specification requires explicit user interaction (clicking file input) before JavaScript can access files.
Email Client Comparison: Attachment Support
| Email Client | Manual Attach | Paste Images | Drag & Drop | API Support |
|---|---|---|---|---|
| Gmail (Web) | ✅ | ✅ | ✅ | ✅ (Gmail API) |
| Outlook (Desktop) | ✅ | ✅ | ✅ | ✅ (MAPI/EWS) |
| Apple Mail | ✅ | ✅ | ✅ | ❌ |
| Thunderbird | ✅ | ✅ | ✅ | ✅ (Extensions) |
| Mobile Apps | ✅ | ⚠️ | ❌ | ✅ (Platform dependent) |
Key insight: All clients support manual attachment, but programmatic attachment requires API access and authentication—something a simple mailto link cannot provide.
Decision Tree: Choosing Your Solution
Do you MUST have attachments (not optional)?
│
├─ YES → Do users need to upload BEFORE emailing?
│ │
│ ├─ YES → Use Alternative #1 (Cloud Storage Links)
│ │ or Alternative #3 (Contact Form)
│ │
│ └─ NO → Can you trust users to attach manually?
│ │
│ ├─ YES → Use Alternative #2 (Body Template)
│ │
│ └─ NO → Use Alternative #3 (Required Form)
│
└─ NO → Simple mailto is fine!
Use our [generator](/) for perfect syntax
Common Questions
Q: What about the vnd.ms-outlook URI scheme?
Some Windows apps use vnd.ms-outlook:// for attachments, but:
- Only works in Outlook for Windows
- Requires MAPI profile configuration
- Blocked by most browsers for security
- Not standardized or cross-platform
Not recommended for web development.
Q: Can I use JavaScript to programmatically attach files?
No. The Web API File interface requires user interaction:
// ❌ Can't create File from path
new File('/path/to/file.pdf'); // Security error
// ✅ Must come from user input
<input type="file" onchange="e => {
const file = e.target.files[0]; // This works
}">
Q: What about using FormData with mailto?
FormData is for HTTP POST requests (forms), not mailto links:
// ❌ This doesn't make sense
const formData = new FormData();
formData.append('file', file);
window.location.href = `mailto:[email protected]`; // Can't pass FormData
Best Practices Summary
- Never promise attachments in mailto links
- Use cloud storage for reliable file sharing
- Provide clear instructions if user must attach manually
- Test mobile experience (most users are mobile)
- Consider forms for better UX and tracking
- Include file size limits to avoid email bounces
- Use secure storage with expiration for sensitive files
Conclusion
While mailto links cannot natively attach files, the workarounds are mature and well-supported:
Best Solutions:
- Cloud storage links (professional, scalable)
- Contact forms (full control, best UX)
- Body templates (simple, zero cost)
Avoid:
- ❌ Promising native attachment support
- ❌ Using deprecated
mapi:protocol - ❌ Attempting to embed files in URLs
Need a perfect mailto link for your use case? Our free generator handles all edge cases and provides QR codes automatically.
Related Resources:
- Complete Mailto Link Syntax Guide
- Mailto Link Troubleshooting
- Mailto vs Contact Forms Comparison
- Stop Using Mailto for Forms
- Browse All Articles
- Developer Cheatsheets
Written by MailtoMaker Team
We are a team of web developers and email marketing experts dedicated to simplifying email link creation. Our mission is to help developers and marketers build perfect mailto links without the hassle.