Does Email Strip EXIF Data? We Built the Messages and Read the Bytes Back
Short answer: no. Sending a JPEG as a normal email attachment does not strip EXIF. The metadata is still there, byte for byte. MIME’s transfer encoding is defined to be reversible: RFC 2045 §6.2 requires the decoder to restore “the original sequence of octets which was encoded”. Base64 is a byte-to-ASCII representation, not an image operation, so it never opens the JPEG and never looks at the EXIF block. In our local test, an attachment sent through a real MIME message came back with the same 201,441 bytes, the same 14 EXIF fields, the same GPS block, and the same XMP and IPTC segments.
The thing that actually removes EXIF is re-encoding the image before you attach it — a client that resizes, compresses or “optimises” the photo. That is the same mechanism we found for WhatsApp and Telegram, and it has nothing to do with email itself. We built and parsed real MIME messages locally for this test; we did not send mail through Gmail, Outlook or any provider, so provider-side behaviour is explicitly outside what we measured.
What we tested, what we documented, and what we could not test
This article separates three kinds of claim. Keeping them apart is the whole point.
Documented. We fetched and quote four primary sources, all linked below: RFC 2045 (MIME Part One), RFC 2183 (Content-Disposition), Gmail’s official attachment help page and the Python email.message documentation. Every quoted sentence on this page was read from those documents.
Measured. Every number in the results table came from e18_local_test.py, run on this machine with Python 3.13, Pillow 12.3.0, piexif 1.1.3 and the Python standard library email package. We constructed real MIME messages, serialised them to bytes, parsed them back, extracted the attachment payload and compared it byte for byte against the source file. This part is a genuine local measurement, not an inference from documentation.
Not tested. We did not send an email through any provider, did not receive one, did not log into a mail client, and did not inspect what a server does in transit. So we make no claim about Gmail’s, Outlook’s or any provider’s server-side handling, about mail gateways that rewrite attachments, or about what a specific client’s “insert photo” button does before it hands bytes to MIME. Where this page discusses those, it is labelled as inference.
That last boundary matters. Earlier articles in this series had to work from documentation because we could not run the platform. Email is different: MIME is a published, implementable protocol, so the core question is testable without an account.
RFC 2045: the transfer encoding is required to be reversible
The single most important sentence for this question is in §6.2 of RFC 2045. It defines what a Content-Transfer-Encoding is allowed to be:
“The transformation part of any Content-Transfer-Encodings specifies, either explicitly or implicitly, a single, well-defined decoding algorithm, which for any sequence of encoded octets either transforms it to the original sequence of octets which was encoded, or shows that it is illegal as an encoded sequence.”
In other words, the standard does not permit a transfer encoding to quietly alter the payload. Decoding must give back the original bytes. EXIF, GPS, XMP and IPTC are just bytes inside the JPEG file; if the whole file comes back unchanged, all of them come back unchanged.
§6.8 describes the base64 encoding that essentially every binary attachment uses: “The Base64 Content-Transfer-Encoding is designed to represent arbitrary sequences of octets in a form that need not be humanly readable”, and “the encoded data are consistently only about 33 percent larger than the unencoded data”. The mechanism is purely arithmetic: “The encoding process represents 24-bit groups of input bits as output strings of 4 encoded characters.” Three input bytes become four ASCII characters; no JPEG decoder is involved.
§6.2 also explains why base64 is the practical choice. The labels 7bit, 8bit and binary “all mean that the identity (i.e. NO) encoding transformation has been performed”, but the RFC states plainly that “there are no circumstances in which the “binary” Content-Transfer-Encoding is actually valid in Internet mail”. Binary image data therefore gets base64-encoded for transport. Our measurement below confirms the Python standard library does exactly that by default.
Inference, stated as such: because the standard requires byte reversibility and base64 performs no image decoding, a compliant attachment path cannot strip EXIF as a side effect. That is an inference from the specification; the byte-for-byte result in the next sections is the measurement that backs it up.
Attachment or inline: the difference is presentation, not bytes
People often assume that dragging a picture into the message body is a different kind of transfer from adding it as a file. At the MIME layer it is not. RFC 2183 defines the two Content-Disposition values purely in terms of how a mail client should present the part:
“A bodypart should be marked `inline’ if it is intended to be displayed automatically upon display of the message.” (§2.1)
“Bodyparts can be designated `attachment’ to indicate that they are separate from the main body of the mail message, and that their display should not be automatic…” (§2.2)
The RFC introduces the header as a way to “convey presentational information”. It does not describe a transformation of the body data. The Python docs likewise say add_attachment() “can be used both for explicit attachments (Content-Disposition: attachment) and inline attachments (Content-Disposition: inline)”. That documentation does not state which transfer encoding a binary payload gets, so we measured it rather than quoting a claim it never makes.
Our two base64 paths differed only in that header and in the extra HTML part carrying cid:photo1. Both delivered the identical 201,441-byte payload with identical SHA-256 prefix 838b01285920d96a. All 14 EXIF fields, the GPS block, XMP and IPTC survived in both.
Inference: when a mail app offers “insert photo” alongside “attach file”, any difference in metadata would come from what the app does to the image before building the MIME message, not from Content-Disposition. We did not test any app’s insert flow.
What Gmail's own help page says, and what it does not say
We read Gmail’s official help page “Send attachments with your Gmail message” directly. It documents size limits, not metadata:
“For personal Gmail accounts, the limit is 25 MB.”
“If your total attachment size is greater than the limit, Gmail automatically removes the attachment and adds it as a Google Drive link in the email.”
It also says “Add an image by dragging it directly into the compose window”, which is the inline path discussed above.
The page does not contain the words EXIF, metadata, compression or original quality, and it makes no statement about whether an attached file is altered. We are reporting that absence, not reading a conclusion into it: an absent statement is not evidence that stripping does or does not happen. It simply means the help page gives us nothing to cite on the subject.
One documented path change is worth knowing: above 25 MB the attachment is replaced with a Drive link. At that point the image is no longer an email attachment at all, and the MIME analysis on this page no longer applies. That is a size rule, not a metadata rule.
Our measurement setup
All numbers below are from e18_local_test.py, run locally on 2026-11-04. The script and its raw output (e18_test/e18_results.json, plus the generated .eml files and extracted attachments) are on this machine, so the whole test is reproducible.
Source file. An 800×600 JPEG, 201,441 bytes, built with Pillow. We injected 14 EXIF fields including a GPS block and deliberately set Orientation = 6. We then appended an independent APP1/XMP segment and an APP13/IPTC segment, so the file carries three separate APP markers (0xE1 EXIF, 0xE1 XMP, 0xED IPTC). That matters: it lets us tell “EXIF survived” apart from “the whole file survived”.
Procedure. For each path we built a real multipart/mixed or multipart/related message with email.mime, serialised it with as_bytes(policy=SMTP), parsed it back with BytesParser, extracted the image part with get_payload(decode=True), then compared SHA-256, counted EXIF fields, checked for GPS and scanned the APP segments for XMP and IPTC bytes. This is a genuine round trip through a serialised message, not a call to an encoder and decoder back to back.
Paths. P0 uses whatever transfer encoding the standard library picks by default; P1 explicitly uses base64 with Content-Disposition: attachment; P2 uses base64 with Content-Disposition: inline and a Content-ID; P3 uses quoted-printable; P4 uses 8bit; P5 re-encodes the JPEG first (Pillow decode → JPEG quality 85, no explicit EXIF) and then attaches it with base64, as a control.
Results: six paths, byte for byte
Every row is a locally measured result. “Identical” means the extracted attachment was byte-for-byte equal to the 201,441-byte source file.
| Path | CTE seen | Disposition | Attachment bytes | EXIF fields | GPS | XMP | IPTC | Identical to source |
|---|---|---|---|---|---|---|---|---|
| Source file | — | — | 201,441 | 14 | yes | yes | yes | — |
| P0 Python default | base64 | attachment | 201,441 | 14 | yes | yes | yes | yes |
| P1 base64 attachment | base64 | attachment | 201,441 | 14 | yes | yes | yes | yes |
| P2 base64 inline | base64 | inline | 201,441 | 14 | yes | yes | yes | yes |
| P3 quoted-printable | quoted-printable | attachment | 203,051 | 14 | yes | yes | no | no |
| P4 8bit | 8bit | attachment | 203,051 | 14 | yes | yes | no | no |
| P5 re-encoded, then attached | base64 | attachment | 111,829 | 0 | no | no | no | no |
The three base64 paths returned SHA-256 prefix 838b01285920d96a, identical to the source. P0 also answers the “what does a normal library actually do” question: the standard library picked base64 without being told to. Mail size grew from 201,441 bytes to 276,322 bytes (a ratio of 1.3717), close to the “about 33 percent larger” figure in RFC 2045 §6.8 — the small excess is the headers and the text part.
The compressed control P5 is the only path where EXIF disappeared: 0 fields, no GPS, no XMP, no IPTC, and the pixel hash changed. It was still delivered through base64, perfectly intact — intact as the already-stripped file. The metadata was gone before MIME saw it.
The one thing that actually strips EXIF is re-encoding
This series keeps arriving at the same variable. Across four different pipelines, metadata survives or dies depending on one question: did the image get decoded and re-encoded?
- Does Discord remove EXIF? — Discord documents using
piexifto strip EXIF; our local reproduction cleared all 30 fields but left independent XMP and IPTC segments standing. - Does WhatsApp remove EXIF? — its re-encoding photo path dropped EXIF, XMP and IPTC, while the original-bytes document path preserved all three. Higher quality settings did not change the metadata outcome.
- Does Telegram remove EXIF? — the open-source client decodes into an Android
Bitmap, which cannot carry EXIF; the file path sends original bytes. - Email, measured here — a plain attachment sends original bytes, so EXIF survives; a re-encoded image arrives with none.
The unified finding is this: transport is not the variable. A single decode-and-re-encode step is. Which is why “does email strip EXIF” is slightly the wrong question — the useful question is whether your mail client re-encoded the photo before attaching it. We cannot answer that for any specific client, because we did not test any client.
The quoted-printable / 8bit trap: a file can open while its bytes have changed
Our P3 and P4 rows are the most interesting result, and the easiest to misread. Both produced a 203,051-byte attachment — 1,610 bytes larger than the source — with EXIF still reporting 14 fields, GPS still present, XMP still present, but IPTC gone. The JPEG still opened. If you only checked “can I see the photo and does it have EXIF”, you would call this a pass.
The 1,610 bytes have an exact explanation. The source JPEG contains 1,092 bare LF bytes and 518 bare CR bytes — 1,610 in total — inside its compressed scan data. Under these line-oriented transfer encodings, each of those was normalised to a CRLF pair, adding one byte per occurrence; the 518 bare CR bytes additionally came back as LF, which is the 518 equal-length 0x0D → 0x0A differences we counted after collapsing CRLF back to LF. Compressed image data is arbitrary binary; rewriting bytes inside it changes the file even when a tolerant decoder still renders the picture.
RFC 2045 §6.7 anticipates exactly this. Its “WARNING TO IMPLEMENTORS” reads: “If binary data is encoded in quoted-printable, care must be taken to encode CR and LF characters as “=0D” and “=0A”, respectively. In particular, a CRLF sequence in binary data should be encoded as “=0D=0A”. Otherwise, if CRLF were represented as a hard line break, it might be incorrectly decoded on platforms with different line break conventions.” The same section advises that “A higher level of confidence is offered by the base64 Content-Transfer-Encoding” and, where line-break alterations would corrupt data, “it is probably more sensible to use the base64 encoding rather than the quoted-printable encoding”.
§2.8 defines 8bit data as short lines where “CR (decimal value 13) and LF (decimal value 10) octets only occur as part of CRLF line separation sequences”. A JPEG does not satisfy that, and §6.2 forbids labelling non-line-oriented unencoded data as anything other than binary. So P3 and P4 are deliberately non-compliant labelings of binary data; we included them to show what breaks, not to suggest real mail clients do this.
Scope of this result, stated plainly: the byte rewriting we observed is how Python’s BytesParser handled those two labelings in our test harness. It is a measurement about this implementation, not a claim about every mail client, gateway or server. The general point it does support is methodological: “the file opens” is not proof that metadata is intact. Only a byte-level comparison is.
So does email strip EXIF? The answer with its honest edges
For the MIME attachment path we tested: no. A base64-encoded JPEG attachment came back byte-for-byte identical, with all 14 EXIF fields, GPS, XMP and IPTC intact, whether it was labelled attachment or inline. That is a measurement, and it follows directly from a standard that requires reversible decoders.
The honest edges are where we stop measuring and start listing unknowns:
- We did not send or receive mail through Gmail, Outlook, or any provider. Provider-side handling, attachment rewriting gateways and virus-scanning proxies were not tested.
- We did not test a mail client’s “insert photo”, “resize” or “optimise” flow. If a client re-encodes before attaching, our P5 control shows the metadata is gone regardless of how faithful the email transport is. Whether any given client does this is unknown to us.
- We did not test what happens after a recipient forwards an attachment, or downloads it through a webmail proxy that generates a preview. Each of those is a fresh opportunity for re-encoding.
- Gmail’s documented 25 MB rule replaces an oversized attachment with a Drive link. Our MIME analysis does not cover that path.
So the practical statement is narrow and defensible: email transport, as specified and as measured here, does not strip EXIF. If EXIF is missing from a photo someone emailed you, look for a re-encoding step before or after the mail, not inside MIME. That is an inference about where to look, not a claim that we observed it in any particular product.
What to actually do about it
If you want to keep the metadata: attach the original file rather than a resized copy, and avoid any client-side “compress” or “optimise” option. After the recipient downloads it, have them verify rather than assume — how to view EXIF data walks through reading the fields back. A file that opens correctly is not proof, as our P3 and P4 rows show; if the bytes matter, compare hashes.
If you want the metadata gone: strip it locally before you attach. See how to erase EXIF data. Do not rely on the mail service to clean the file for you — a compliant attachment path is designed to deliver the bytes you gave it, which is exactly why it preserves EXIF in the first place.
If you are dealing with screenshots instead of camera photos: the starting point is different. Screenshots usually carry little or no camera EXIF at all, which is a separate question from whether a transport removed it. Our page on do screenshots have exif data covers what is typically in a screenshot to begin with.
If a photo arrived by email and you are trying to work out whether it is an original or a screenshot: the metadata test only helps once you know what the file should have contained. The do screenshots have exif data comparison is the useful reference here, and what EXIF data is explains the field groups (camera, exposure, GPS, orientation) you would be checking for. Orientation is a good canary: in our test the source carried Orientation = 6, and it survived every byte-identical path.
One last practical check. If you are sending a large original to preserve metadata, remember the documented 25 MB Gmail threshold from the official help page: past it, the file becomes a Drive link and this entire MIME analysis stops applying.
FAQ
Does email strip EXIF data from photo attachments? No, not on the path we tested. We built real MIME messages, sent a 201,441-byte JPEG through them and parsed it back: the attachment was byte-for-byte identical, with all 14 EXIF fields, the GPS block, XMP and IPTC intact. RFC 2045 §6.2 requires a transfer encoding to decode back to “the original sequence of octets which was encoded”. We did not test any real mail provider.
Does Gmail remove EXIF data from attached photos? We cannot say, because we did not send mail through Gmail. Gmail’s official attachment help page documents a 25 MB size limit and says oversized attachments are replaced with a Google Drive link; it does not contain the words EXIF, metadata, compression or original quality, and makes no statement about files being altered. We are not treating that silence as an answer either way.
Does inserting a photo into the message body preserve EXIF? At the MIME layer, yes in our test. We compared Content-Disposition: inline (with a Content-ID and an HTML part) against Content-Disposition: attachment. Both returned the identical 201,441-byte payload with identical metadata. RFC 2183 defines inline and attachment as presentation semantics, not data transformations. What a specific app does to the image before building the message is untested here.
Does base64 encoding change my image file? No. Base64 represents three input bytes as four ASCII characters; RFC 2045 §6.8 says the encoded data are “consistently only about 33 percent larger than the unencoded data”. In our measurement the 201,441-byte file became part of a 276,322-byte message, and the extracted attachment was still exactly 201,441 bytes with the same SHA-256. Base64 never decodes the JPEG.
Why did quoted-printable and 8bit change the bytes in your test? Because they are line-oriented encodings applied to binary data that contains bare CR and LF bytes. Our source JPEG had 1,092 bare LF and 518 bare CR bytes; both were normalised to CRLF, producing a 203,051-byte file and breaking the IPTC segment, though the JPEG still opened and EXIF still read 14 fields. RFC 2045 §6.7 explicitly warns that binary CR and LF must be encoded as =0D and =0A. This is a result from Python’s parser in our harness, not a claim about all mail software.
Does compressing or resizing a photo before attaching remove EXIF? In our control path, yes. We decoded the source JPEG and re-encoded it at quality 85 without explicitly carrying EXIF, then attached it with base64. The delivered file was 111,829 bytes with 0 EXIF fields and no GPS, XMP or IPTC. The email transport delivered that stripped file perfectly; the metadata was lost at the re-encoding step, before MIME was involved.
How can I check whether an attachment still has its EXIF? Read the fields back from the downloaded file with an EXIF viewer, and for a strict answer compare its hash with the original. A JPEG can open normally while its bytes have changed — our quoted-printable and 8bit paths still displayed 14 EXIF fields and GPS yet had lost their IPTC segment. See our guide on how to view EXIF data.
What happens to EXIF when an attachment exceeds Gmail's size limit? Gmail’s help page says that above 25 MB “Gmail automatically removes the attachment and adds it as a Google Drive link in the email”. At that point the image is not an email attachment, so the MIME analysis in this article does not apply. We did not test what Drive stores, and the help page makes no statement about metadata.
Related reading
- Do screenshots have EXIF data? — the baseline question: what metadata a screenshot carries before any app or transport touches it.
- Does Telegram remove EXIF? (we read the open-source client) — the same decode-versus-original-bytes split, verified against the official Android client source.
- Does WhatsApp remove EXIF? (we tested the compression) — why higher quality settings did not change the metadata outcome on the re-encoding path.
- Does Discord remove EXIF? (we reproduced its stripping code) — the one platform that documents stripping EXIF, and why XMP and IPTC survived it.
- What is EXIF data? — the field groups — camera, exposure, GPS, orientation — that a byte-identical transfer preserves.
- How to erase EXIF data — strip metadata locally before attaching, since a faithful email transport will not do it for you.
- How to view EXIF data — read the fields back from a downloaded attachment to verify rather than assume.