CF7 File Uploads Not Arriving as Email Attachments: The Hidden Third Field Nobody Documents

Two developers posted the same issue on the WordPress support forums within a week of each other. Both had set up Contact Form 7 file uploads correctly by every tutorial they could find. Both had [your-file] in the Mail tab. Both confirmed the file was reaching the server. Neither received the file as an email attachment.
The resolution came from a community member who found the answer in a YouTube video, not in the CF7 documentation. Here is what that video showed:
There is a third field in CF7's Mail tab called File Attachments. It is below the message body. It is hidden unless you scroll. It is not mentioned in CF7's official documentation. Without it, files upload to your server but are never attached to the outgoing email.
This post documents all three required placements, explains what each one actually does, covers the filetypes wildcard problem, explains where uploaded files go and why Flamingo shows a number instead of a link, and covers how to route file uploads to permanent storage via API.
Why CF7 File Uploads Have Three Separate Placements
CF7 separates the concerns of rendering the upload field, referencing the file in email content, and actually attaching the file to the email. These are three distinct functions handled by three distinct tag placements in different parts of the CF7 configuration.
| Placement | Tab | Field | Function |
|---|---|---|---|
[file field-name ...] |
Form | Form editor body | Renders the <input type="file"> element in the HTML form |
[field-name] |
Message Body | Inserts the uploaded filename as plain text in the email body | |
[field-name] |
File Attachments | Actually attaches the file to the outgoing email as a binary attachment |
The second and third placements use identical syntax but are in different fields. This is the source of all the confusion. A developer who puts the tag in the message body assumes the file will be attached. It will not. The message body placement only outputs the filename string. The File Attachments field is what causes the actual binary attachment to appear in the recipient's email client.
Complete Configuration Walkthrough
Form Tab
Use the File button in CF7's form editor toolbar (not the tag generator) to insert the file field. The toolbar button opens a dialog that generates the tag with correct syntax:
[file your-file filetypes:pdf|doc|docx|jpg|png limit:5mb]
Field name: Any valid identifier. Avoid spaces. your-file, uploaded-document, company-logo are all fine.
filetypes: Pipe-separated list of allowed file extensions or MIME types. Do not use wildcards like image/* in production (covered below).
limit: Maximum file size in kb or mb. This cannot exceed your server's upload_max_filesize PHP directive. If CF7 accepts the file but the server rejects it, the server limit is lower than your CF7 limit.
Make a field optional by omitting the asterisk:
[file your-file ...] <- optional, form submits without a file
[file* your-file ...] <- required, form blocked if no file selected
Mail Tab: Message Body
In the Mail tab, add the field tag where you want the filename to appear in the email body:
From: [your-name] <[your-email]>
Message:
[your-message]
Uploaded file: [your-file]
This outputs the filename as text. It does not attach the file. It is optional — if you only want the attachment without mentioning it in the body, skip this placement.
Mail Tab: File Attachments Field
Scroll below the Message Body field in the Mail tab. There is a smaller field labelled File Attachments. Add the same tag here:
[your-file]
This is the placement that attaches the binary file to the email. Without it, the upload completes, the file lands on your server in wp-content/uploads/wpcf7_uploads/, the email is sent with the filename in the body, and then CF7 deletes the temporary file. The recipient receives an email mentioning a file that was never attached.
For multiple file fields, add each tag on its own line in the File Attachments field:
[document-upload]
[photo-upload]
[signed-form]
The Filetypes Wildcard Problem
The first developer's form tag used:
[file your-file filetypes:audio/*|video/*|image/* limit:1mb]
CF7 supports wildcard MIME type syntax, but it relies on the server's MIME type detection library to resolve them correctly. On some server configurations, particularly shared hosting and servers running older versions of libmagic, wildcard resolution fails and valid file types get rejected.
The safer approach is explicit types:
[file your-file filetypes:image/jpeg|image/png|image/gif|image/webp limit:1mb]
Or using file extensions, which are more readable and work consistently:
[file your-file filetypes:jpg|jpeg|png|gif|webp|mp3|mp4|mov limit:1mb]
File extension matching in CF7 is case-insensitive. jpg covers both jpg and JPG uploads.
Why Flamingo Shows a Number, Not a Link
The first developer saw a number in Flamingo (CF7's companion submission logging plugin) instead of a clickable file link. This is expected behaviour, not a bug.
CF7 stores uploaded files temporarily in wp-content/uploads/wpcf7_uploads/ during form processing. Flamingo records the submission data including a reference to the temporary file. After CF7 sends the email, it deletes the temporary file. Flamingo's record has the file reference (a numeric ID or temporary path) but the file itself is gone.
Flamingo is a form submission logger, not a file storage system. It was not designed to preserve uploaded files permanently.
If you need permanent access to uploaded files after submission:
Option A: CF7 storage plugins
Plugins like "CF7 to Post", "CF7 File Download Manager", or "Contact Form Submissions" can save uploaded files permanently to the WordPress media library or a designated uploads folder alongside the submission record.
Option B: Forward to external cloud storage via API
Contact Form to API can POST form submission data to an external webhook endpoint where a workflow can save the file to S3, Google Drive, Dropbox, or any cloud storage provider. This keeps files out of your WordPress server's storage and in a purpose-built storage system.
The workflow:
CF7 processes the submission
Contact Form to API fires a webhook with form field values
The webhook handler retrieves the temporary file before CF7 deletes it and saves it to cloud storage
The file URL from cloud storage is stored in your CRM or database
This requires the webhook handler to be fast enough to retrieve the file before CF7's cleanup runs. CF7 deletes files immediately after wpcf7_mail_sent completes. The webhook handler needs to be in the same request cycle, which means using wpcf7_before_send_mail rather than a delayed webhook if you need to intercept the file before deletion.
Server Configuration: When PHP Limits Override CF7 Limits
CF7's limit attribute cannot override the server's PHP upload configuration. If your CF7 tag says limit:10mb but the server has upload_max_filesize = 2M, files larger than 2MB will fail at the PHP level before CF7 ever sees them.
Check the relevant PHP directives:
# From terminal on your server
php -i | grep -E "upload_max_filesize|post_max_size|max_file_uploads"
Or add a temporary diagnostic page:
// In a temporary PHP file on your server — delete after checking
<?php
echo 'upload_max_filesize: ' . ini_get('upload_max_filesize') . '<br>';
echo 'post_max_size: ' . ini_get('post_max_size') . '<br>';
echo 'max_file_uploads: ' . ini_get('max_file_uploads') . '<br>';
To increase these limits on shared hosting, add to php.ini or .htaccess (if your host permits):
php_value upload_max_filesize 10M
php_value post_max_size 12M
post_max_size must be larger than upload_max_filesize because the POST body includes other form fields in addition to the file.
Making Fields Optional: The Asterisk Rule
CF7's required field syntax is universal:
[text* required-field] <- asterisk = required
[text optional-field] <- no asterisk = optional
[file* required-upload] <- required file upload
[file optional-upload] <- optional file upload
For a form where uploading a logo is optional (as in the forum thread for a school/organization logo field), remove the asterisk:
[file your-file filetypes:jpg|png|gif limit:1mb]
The form submits successfully whether or not the user selects a file. If selected, the file goes through the upload and attachment flow. If not selected, the File Attachments field in the mail simply sends no attachment.
Summary
| Problem | Cause | Fix |
|---|---|---|
| File uploaded but not attached to email | Missing tag in Mail tab File Attachments field | Add [field-name] to the File Attachments field (scroll down in Mail tab) |
| Flamingo shows a number, no file link | CF7 deletes files after sending — Flamingo does not store files | Use a CF7 storage plugin or forward to cloud storage via API |
image/* wildcard rejecting valid files |
Server MIME detection issue | Use explicit types: `jpg |
| CF7 limit not working as expected | PHP upload_max_filesize override |
Check and increase PHP directives via php.ini or .htaccess |
| Optional field required unexpectedly | Asterisk in the field tag | Remove * from the field tag: [file name] not [file* name] |
The File Attachments field is the missing piece in almost every CF7 file upload problem thread. It is not visible without scrolling, not covered in the official documentation, and not generated by the form tag builder. Once you know it exists, the entire file upload flow makes sense.




