Today I have spent a rather torturous afternoon struggling to solve a quoted printable email formatting issue in @PolicyBee’s new CRM.

You may already know

You may already know, but when emails are sent, they are encoded, known as a content-transfer-encoding.


This encoding is typically handled either in 7bit, base64 or quoted-printable.

Quoted-printable mail consists primarily of US-ASCII characters, but from time to time, usually when a copy writer has copied from Word into their wysiwyg editor and carried across all of that ‘special’ formatting, such as a curly apostrophe, the mail will contain non-standard characters – and this is exactly what I had to deal with today.

A quoted-printable email will contain various 8 bit values and some are encoded in 3 characters, prefixed with the equals sign followed by a hex value, for example, “=3D” represents “=”. This is typically the only decoding that is required for a quoted-printable email.

The curly quote symbol however, is an example of how some chracters need further encoding to survive the transfer. This symbol uses an expensive nine bytes (compared to one byte for a simple apostrophe) with the following sequence: =E2=80=99.

This means that the code to handle the decoding of quoted printable email must be extended somewhat to support these special characters that will appear 0.1% of the time.

A gift, from me, to you

There is particularly limited posting online about solutions in C# to this problem, so to aid my fellow developer, here is my code to decode a quoted printable email:

<code>1:      private string DecodeQuotedPrintable(string input)  <br>2:      {  <br>3:        var occurences = new Regex(@"(=[0-9A-Z][0-9A-Z])+", RegexOptions.Multiline);  <br>4:        var matches = occurences.Matches(input);  <br>5:        foreach (Match m in matches)  <br>6:        {  <br>7:          byte[] bytes = new byte[m.Value.Length / 3];  <br>8:          for (int i = 0; i < bytes.Length; i++)  <br>9:          {  <br>10:            string hex = m.Value.Substring(i * 3 + 1, 2);  <br>11:            int iHex = Convert.ToInt32(hex, 16);  <br>12:            bytes[i] = Convert.ToByte(iHex);  <br>13:          }  <br>14:          input = input.Replace(m.Value, Encoding.Default.GetString(bytes));  <br>15:        }  <br>16:        return input.Replace("=rn", "");  <br>17:      }  <br></code>

After debugging my way around the CRM, finally tracking down where the issue originated and then applying the solution… I am totally spent for the day so if you have any questions, don’t expect a swift reply. @dpitt