Log in

Contact form with file upload

Two changes to an ordinary contact form: enctype on the form element and an input of type file. The attachment is delivered with the notification email, so you open it from your inbox like any other attachment.

Live preview: this is the HTML and CSS below, rendered as-is.

Replace YOUR_FORM_ID with a form of your own and this sends to your inbox.

Create your form
contact.html
<form action="https://submit.formpost.ai/YOUR_FORM_ID" method="POST" enctype="multipart/form-data">
  <h2>Send us a file</h2>
  <p class="lede">Attach a brief, a screenshot, or anything else that helps.</p>

  <label for="name">Name</label>
  <input id="name" type="text" name="name" required>

  <label for="email">Email</label>
  <input id="email" type="email" name="email" required>

  <label for="attachment">Attachment</label>
  <input id="attachment" class="file" type="file" name="attachment"
         accept=".pdf,.png,.jpg,.jpeg,.docx">
  <p class="hint">PDF, image or Word document, up to 10 MB.</p>

  <label for="message">Message</label>
  <textarea id="message" name="message" rows="3" required></textarea>

  <button type="submit">Send message</button>
</form>
contact.css
body {
  margin: 0;
  padding: 32px 16px;
  background: #fafafa;
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  color: #171717;
}

form {
  display: flex;
  flex-direction: column;
  max-width: 430px;
  margin: 0 auto;
  padding: 28px;
  background: #fff;
  border: 1px solid #ededed;
  border-radius: 14px;
}

h2 {
  margin: 0 0 4px;
  font-size: 20px;
}

.lede {
  margin: 0 0 20px;
  font-size: 14px;
  color: #737373;
}

label {
  margin-bottom: 6px;
  font-size: 13px;
  font-weight: 600;
  color: #404040;
}

input,
textarea {
  box-sizing: border-box;
  font: inherit;
  margin-bottom: 16px;
  padding: 10px 12px;
  color: #171717;
  background: #fff;
  border: 1px solid #d4d4d4;
  border-radius: 8px;
}

input:focus,
textarea:focus {
  border-color: #171717;
  outline: 2px solid rgba(23, 23, 23, 0.12);
}

textarea {
  resize: vertical;
}

button {
  padding: 11px 16px;
  font: inherit;
  font-weight: 600;
  color: #fff;
  background: #171717;
  border: 0;
  border-radius: 8px;
  cursor: pointer;
}

.hint {
  margin: -8px 0 16px;
  font-size: 12px;
  color: #a3a3a3;
}

.file {
  padding: 10px 12px;
  background: #fafafa;
  border-style: dashed;
  cursor: pointer;
}

.file::file-selector-button {
  margin-right: 12px;
  padding: 6px 12px;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  color: #171717;
  background: #fff;
  border: 1px solid #d4d4d4;
  border-radius: 6px;
  cursor: pointer;
}

.file::file-selector-button:hover {
  background: #f5f5f5;
}

enctype is not optional

Without enctype="multipart/form-data" the browser submits only the file's name — not its contents. The form appears to work, the email arrives, and the attachment is simply absent. This is the single most common reason an upload silently does nothing.

<form action="https://submit.formpost.ai/YOUR_FORM_ID" method="POST" enctype="multipart/form-data">

accept filters, it does not enforce

The accept attribute changes what the file picker offers by default. It is a convenience, not a restriction — anyone can switch the picker to All Files, and anything posting directly to the endpoint never saw your markup at all. Treat it as help for honest visitors and nothing more.

Size limits and what happens at the edge

PlanMaximum per file
FreeUploads not available
Pro10 MB
Business25 MB

A file over the limit gets a 413 with a message that says so, rather than a truncated submission you find out about later. Say the limit in your own markup too — the hint under the field above is there so nobody discovers it by failing.

What is kept, and what is not

The file travels with the notification email and that email is your copy. The submission record keeps the filename, type and size so you can see what was sent, but not the file itself — which means your archive stays small and there is no second copy of somebody's CV sitting in storage indefinitely.

Turn uploads on in your form settings first. Until you do, the file input is ignored and the rest of the submission goes through as normal.

Questions about this contact form

How do I add a file upload to an HTML contact form?
Add enctype="multipart/form-data" to the form element and an input with type="file" and a name. Both are required — the input alone submits just the filename.
Why is my attachment not arriving?
Almost always the missing enctype. Check that next, that the file input has a name attribute, and that uploads are switched on in the form settings.
What is the maximum file size?
10 MB per file on Pro and 25 MB on Business. Uploads are not available on the free plan. Anything larger is rejected with a 413 and an explanation rather than being quietly truncated.
Can visitors upload more than one file?
Add the multiple attribute to the file input, or use several file inputs with different names. Each file is subject to the same per-file limit.

Related examples

Or go back to all 21 contact form examples.

Give this form an endpoint

Formpost takes the submission, emails it to you and keeps a searchable copy. Free for 250 messages a month, with unlimited forms and no card.