Signature
quoted_printable_encode(string $string): stringPurpose
quoted_printable_encode() converts a string that may contain 8-bit bytes into the quoted-printable form described in RFC 2045, section 6.7. Quoted-printable is a transfer encoding used in email and MIME parts. Most characters of mostly-ASCII text stay readable, while bytes that are not safe for 7-bit transports are written as an equals sign followed by two uppercase hexadecimal digits. For example, the byte 0xC3 becomes =C3.
The function works on bytes, not characters. A UTF-8 letter such as ö is two bytes, so it becomes two escape sequences. It does not need the IMAP extension, unlike the similar imap_8bit().
Signature
Parameters and defaults
$string: the input string to encode. It has no default and is required. Any byte sequence is accepted, whether or not it is valid UTF-8.
There are no other parameters, so you cannot choose a line length or a line ending style.
Return value and failure cases
The function returns the encoded string. It does not return false and does not signal an error for unusual input. An empty string produces an empty string. The result is always plain ASCII, which is why the output is safe to place in a MIME body that declares Content-Transfer-Encoding: quoted-printable.
Because the parameter is typed as string, passing an array or an object without __toString() throws a TypeError. In default non-strict mode, scalars such as integers are converted to strings first.
Example 1: encoding and decoding text
The following example encodes a German sentence, checks the encoded length, and decodes it again. The two umlauts each take six characters in the output (=C3=B6 and =C3=84).
$encoded = quoted_printable_encode('Möchten Sie ein paar Äpfel?');
echo $encoded, "\n";
echo strlen($encoded), "\n";
echo quoted_printable_decode($encoded), "\n";M=C3=B6chten Sie ein paar =C3=84pfel? 37 Möchten Sie ein paar Äpfel?
Plain letters and ordinary spaces pass through untouched, so the result stays easy to read.
Example 2: special characters and line endings
The equals sign itself must be escaped, otherwise a decoder would mistake it for the start of an escape sequence. Control characters such as tab and a lone line feed are escaped too. A carriage return followed by a line feed (CRLF) is the one newline form that is kept as a real line break.
$inputs = ['a=b', "x\r\ny", "x\ny", "tab\t"];
$encoded = array_map('quoted_printable_encode', $inputs);
echo json_encode($encoded, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";["a=3Db","x\r\ny","x=0Ay","tab=09"]
The JSON output shows the CRLF as the visible characters \r\n, while the bare \n became =0A.
Example 3: soft line breaks
Quoted-printable lines must stay short. When a line would grow too long, the function inserts a soft line break: an equals sign followed by CRLF. A decoder removes it again, so the original data is restored exactly.
$input = str_repeat('A', 80);
$encoded = quoted_printable_encode($input);
echo json_encode([strlen($encoded), substr_count($encoded, "\r\n"), quoted_printable_decode($encoded) === $input]), "\n";[83,1,true]
The 80 letters are split with one soft break, which adds three bytes, giving 83 bytes in total. Decoding returns the original value.
Edge cases
- Binary data: every byte with the high bit set is escaped, so binary input is encoded safely, but the output can be up to three times larger than the input.
- Lone
\nand\r: only the CRLF pair is kept as a line break. Text with Unix newlines will have each newline escaped as=0A. If you want real line breaks in the result, normalize your input to CRLF first. - Soft breaks are part of the output: the result may contain
=\r\nsequences. Do not search it for words or count its characters as if it were the original text. - Encoded size:
strlen()of the result is not the length of the source text. Check size limits after encoding.
Common mistakes
- Using it for headers. Header values such as a
Subjectneed the MIME encoded-word syntax, for example=?UTF-8?Q?...?=. A raw quoted-printable body is not valid there. Seeiconv_mime_encode()for that job. - Forgetting the MIME headers. Encoding the body is not enough. The message must declare
Content-Transfer-Encoding: quoted-printableand a suitableContent-Typecharset, or the receiver will show the escape sequences literally. - Confusing it with other encodings. It is not
urlencode()(which uses%and encodes spaces differently) and notbase64_encode(). Use the format that the target protocol requires. - Encoding twice. Running the function on already encoded text turns every
=into=3D, which corrupts the message. - Splitting the output manually. Cutting the encoded string at an arbitrary offset can break an
=XXsequence in half. Encode the whole body first and let the function handle line lengths.
Related functions
quoted_printable_decode()reverses the encoding.imap_8bit()behaves similarly but needs the IMAP extension.iconv_mime_encode()builds complete MIME header fields.base64_encode()is an alternative transfer encoding that suits mostly binary data.
Recap
quoted_printable_encode() takes one string and returns an ASCII-safe quoted-printable string. It escapes high-bit bytes, control characters and =, keeps CRLF pairs as line breaks, and inserts soft line breaks to keep lines short. Treat it as a body encoder for MIME content, pair it with the right headers, and use quoted_printable_decode() to get the original bytes back.
Tested examples
$encoded = quoted_printable_encode('Möchten Sie ein paar Äpfel?');
echo $encoded, "\n";
echo strlen($encoded), "\n";
echo quoted_printable_decode($encoded), "\n";
M=C3=B6chten Sie ein paar =C3=84pfel? 37 Möchten Sie ein paar Äpfel?
$inputs = ['a=b', "x\r\ny", "x\ny", "tab\t"];
$encoded = array_map('quoted_printable_encode', $inputs);
echo json_encode($encoded, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
["a=3Db","x\r\ny","x=0Ay","tab=09"]
$input = str_repeat('A', 80);
$encoded = quoted_printable_encode($input);
echo json_encode([strlen($encoded), substr_count($encoded, "\r\n"), quoted_printable_decode($encoded) === $input]), "\n";
[83,1,true]