File uploads
Accept attachments from an ordinary file input. Files are stored with the submission and downloaded from your dashboard.
Before you start
File uploads are included on Pro and Agency. On Free, file parts are dropped and the rest of the submission is stored as normal, so adding a file input never breaks a form. You need an HTML form already posting to your endpoint. If you do not have one yet, start with the quickstart.
- 1
Add a file input
Add an
<input type="file">with aname, and set the form'senctypetomultipart/form-data. Thenameis recorded with each file, so you can tell a CV from a portfolio. Addmultipleto let a visitor pick several files for one input.HTML<form action="https://mtform.co/f/your-form-key" method="POST" enctype="multipart/form-data"> <label>Email <input type="email" name="email" required></label> <label>Message <textarea name="message"></textarea></label> <label>Your CV <input type="file" name="cv" accept=".pdf,.doc,.docx"></label> <label>Photos <input type="file" name="photos" accept="image/*" multiple></label> <button type="submit">Send</button> </form>Without the enctype, the browser sends the file names as plain text instead of the files. Nothing errors; the attachments just never arrive. - 2
Or send it with fetch
If you submit with JavaScript, pass a
FormDataobject as the body. JSON and URL-encoded bodies cannot carry files; only multipart can.JavaScriptconst form = document.querySelector('form'); form.addEventListener('submit', async (event) => { event.preventDefault(); // Do not set Content-Type yourself. The browser adds the multipart boundary. const response = await fetch(form.action, { method: 'POST', headers: { Accept: 'application/json' }, body: new FormData(form), }); const result = await response.json(); console.log(response.status, result); });More on JavaScript submissions, including showing errors inline, is in AJAX & fetch.
- 3
Find your files
Open the submission from Submissions. Attachments are listed under the fields with their name and size. Each download is a link into your dashboard that checks you are signed in and allowed to see the submission, then hands over a short-lived download link. A link copied out of the dashboard stops working for anyone who loses access.
Notification emails, Slack and the other integrations carry the text fields only. Webhooks include a
filesarray with a signed URL for each attachment, valid for one hour.
Limits
| Limit | Value |
|---|---|
| Size of one file | 10 MB |
| Files per submission | 10 |
| All files in one submission | 25 MB |
| Text fields, separately | 256 KB |
Storage is counted across your whole workspace, for every file not yet deleted:
| Plan | Included storage |
|---|---|
| Free | Not included |
| Pro | 1 GB |
| Agency | 10 GB |
When a file is refused
A refused file is dropped and the rest of the submission is still accepted. Losing someone's written enquiry because they attached the wrong thing would be worse than losing the attachment. A file is refused when:
- It is larger than 10 MB, or it would take the submission past 25 MB in total.
- It is file number 11 or later in the same submission.
- Its extension is on the blocked list: executables, scripts, installers and disk images such as
.exe,.bat,.js,.msi,.isoand.php. Ordinary documents, including macro-enabled Office files, are accepted. - Your workspace has used its storage allowance.
The visitor still gets a success response, so check sizes and types in the browser if you want to warn them. The accept attribute in the example above is a good start. The messages we use for these cases are short enough to reuse: “Each file must be under 10 MB.” and “Attach at most 10 files.”
413 with payload_too_large. Nothing from that request is stored. See errors.How files are served
The blocked list is a safety net, not a virus scanner: renaming a file gets around it. What protects you is how files come back out. The type a browser declared is never trusted. PNG, JPEG, GIF, WebP, PDF, plain text and CSV are served as themselves; anything else is served as a generic download, so an uploaded HTML or SVG file cannot run in your browser. Stored names are cleaned of paths and control characters.