How to decode quoted-printable
- Click Quoted-printable → Text above the tool to switch to decoding.
- Paste the encoded text, for example a body part copied from an email’s source, into the input.
- Read the text in the output. If accented letters look wrong, set Charset under the output to the charset named in the part’s
Content-Typeheader, such ascharset=iso-8859-1. - Copy output or Download. Soft line breaks are joined and every
=XXis turned back into its byte.
To encode, leave the direction on Text → Quoted-printable and type or paste the text. Charset under the input decides which bytes non-ASCII characters become.
How quoted-printable works
Quoted-printable (RFC 2045, section 6.7) keeps text readable where it can and escapes only what it must:
- Printable ASCII characters stay as they are, except
=. - Every other byte is written as
=plus two uppercase hex digits. In UTF-8 that means each non-ASCII character becomes two to four escapes. =itself becomes=3D.- A space or tab at the end of a line becomes
=20or=09. - Lines are at most 76 characters. Longer ones are split with a soft line break: an
=at the end of the line, which the decoder removes.
| Text | Quoted-printable |
|---|---|
café | caf=C3=A9 |
Grüße aus München | Gr=C3=BC=C3=9Fe aus M=C3=BCnchen |
100% = €5 | 100% =3D =E2=82=AC5 |
<p style="color:red">Hi</p> | <p style=3D"color:red">Hi</p> |
Caf=E9 decoded as ISO-8859-1 | Café |
In the last row =E9 is a single byte: é in ISO-8859-1 and Windows-1252, and invalid on its own in UTF-8, so the result depends on the charset you decode with.
Text mode and binary mode
By default the encoder treats the input as text. Line breaks stay real line breaks, and, as in Python’s binascii.b2a_qp, if the first line ends in CRLF a bare LF later on becomes CRLF too. That is right for email text, but it changes the bytes.
Tick Encode line breaks (binary) when the exact bytes matter. Line breaks are then written as =0D and =0A, so Hello, CRLF, World becomes Hello=0D=0AWorld, and decoding gives back exactly what went in. For real binary data such as images, Base64 is the better choice anyway.
Quoted-printable or Base64 in email
Mail software picks the Content-Transfer-Encoding per MIME part. Quoted-printable suits text that is mostly ASCII, because it stays readable and grows little. Base64 has a fixed overhead of about 33% and wins once most bytes need escaping:
| Text | UTF-8 bytes | Quoted-printable | Base64 |
|---|---|---|---|
Grüße aus München | 20 | 32 characters | 28 characters |
Привет, мир (Russian) | 20 | 56 characters | 28 characters |
Even German text with three non-ASCII letters in 17 characters is already larger in quoted-printable than in Base64; Cyrillic is twice the Base64 size. To produce the Base64 form with the 76-character lines email requires, use the MIME Base64 encoder. Base64 in email explains how both encodings appear in a message, including attachments and encoded headers.
Reading a whole email
Copying one body part out of a raw message works for a quick look. For a complete .eml file, the EML decoder parses the headers, decodes quoted-printable and Base64 parts with their declared charsets, and lists attachments for download. Quoted-printable also appears outside email, for example in vCard 2.1 files with ENCODING=QUOTED-PRINTABLE; paste the value after the colon here.
Quoted-printable in code
import quopri
quopri.encodestring("café".encode("utf-8")) # b'caf=C3=A9'
quopri.decodestring(b"caf=C3=A9 =3D 5=E2=82=AC").decode("utf-8") # 'café = 5€'
Python’s email package applies the right decoding automatically: msg.get_payload(decode=True) returns the decoded bytes of a part, whichever transfer encoding it uses. The Python page covers the Base64 side.
FAQ
What does =3D mean in an email?
It is an encoded equals sign. In quoted-printable = starts an escape, so a literal = has to be written as =3D, its byte value in hex. You see it a lot in HTML email, as in style=3D"color:red".
Why do lines in the email source end with =?
That is a soft line break. Quoted-printable lines may be at most 76 characters, so longer lines are split and each break is marked with a trailing =. A decoder joins the pieces back into one line.
What does =20 at the end of a line mean?
An encoded space. Mail systems may strip trailing spaces, so quoted-printable protects a space or tab at the end of a line by writing it as =20 or =09.
How do I decode quoted-printable in Python?
quopri.decodestring(data) or binascii.a2b_qp(data) return bytes; call .decode("utf-8") or whichever charset the Content-Type header names.
Can it decode =?UTF-8?Q?...?= subject lines?
Not on this page. Those are RFC 2047 encoded words, which use a related Q encoding with _ for spaces. The EML decoder decodes them in headers, along with quoted-printable bodies.