Code of Conduct
Feature Description
Add an option to Django's console and file EmailBackends to display non-ASCII characters as Unicode (utf-8), rather than the various 7-bit encodings used for SMTP transmission.
Problem
Django's console and filebased EmailBackends output email messages exactly as they would be passed to an SMTP server. That's helpful for debugging SMTP, but not so helpful if you just want to see the content being emailed. And it can be confusing if you aren't familiar with the variety of different encodings needed to represent non-ASCII characters for 7-bit SMTP transmission.
For example, the console EmailBackend might show this for a password reset email. Notice the subject header and message body:
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: base64
MIME-Version: 1.0
Subject: =?utf-8?b?0KHQutC40LTQsNC90L3RjyDQv9Cw0YDQvtC70Y8g0L3QsCDQn9GA0LjQutC70?=
=?utf-8?b?LDQtCDRgdCw0LnRgtGD?=
From: webmaster@django.example.com
To: user@example.com
Date: Sat, 30 May 2026 20:21:35 +0000
Message-ID: 178017249531.136945.18351584476362565960@django.example.com
0JLQuCDQvtGC0YDQuNC80LDQu9C4INGG0LXQuSDQu9C40YHRgiDRh9C10YDQtdC3INGC0LUsINGJ
0L4g0LfRgNC+0LHQuNC70Lgg0LfQsNC/0LjRgiDQvdCwINC/0LXRgNC10LLRgdGC0LDQvdC+0LLQ
u9C10L3QvdGPINC/0LDRgNC+0LvRjyDQtNC70Y8g0L7QsdC70ZbQutC+0LLQvtCz0L4g0LfQsNC/
0LjRgdGDINC60L7RgNC40YHRgtGD0LLQsNGH0LAg0L3QsCDQn9GA0LjQutC70LDQtCDRgdCw0LnR
gtGDLgoK0JHRg9C00Ywg0LvQsNGB0LrQsCwg0L/QtdGA0LXQudC00ZbRgtGMINC90LAg0YbRjiDR
gdGC0L7RgNGW0L3QutGDLCDRgtCwINC+0LHQtdGA0ZbRgtGMINC90L7QstC40Lkg0L/QsNGA0L7Q
u9GMOgpodHRwOi8vZGphbmdvLmV4YW1wbGUuY29tL3Bhc3N3b3JkLXJlc2V0L01nL2Q5ZjB4ei03
YWI0Yjg4ZjQ2MTEzMWJlZjdiMTBiMzI4YzQ3OGM1ZS8K
In many cases, it would be more useful to show the original, unencoded Unicode text:
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Subject: Скидання пароля на Приклад сайту
From: webmaster@django.example.com
To: user@example.com
Date: Sat, 30 May 2026 20:21:35 +0000
Message-ID: 178017249531.136945.18351584476362565960@django.example.com
Ви отримали цей лист через те, що зробили запит на перевстановлення пароля для облікового запису користувача на Приклад сайту.
Будь ласка, перейдіть на цю сторінку, та оберіть новий пароль:
http://django.example.com/password-reset/Mg/d9f0xz-7ab4b88f461131bef7b10b328c478c5e/
Request or proposal
proposal
Additional Details
See (e.g.,) this forum topic. The developer assumed (reasonably, imho) that the base64-encoded message body echoed to the console was a bug.
With the console backend becoming the default for new projects in the 6.1 settings template, we're likely to start seeing similar reports more often.
Implementation Suggestions
[Edit: see updated proposal in a later comment.]
We could add a decode boolean option to the console and filebased backends:
MAILERS = {
"default": {
"BACKEND": "django.core.mail.backends.console.EmailBackend",
"OPTIONS": {"decode": True},
},
}
When decode is True, we'd change the message serialization in write_message() so the original, unencoded text content would be written to the console or file (as Unicode text). I think it would also be good to update the new-project settings template to include the decode option as shown above.
Some experimentation would be needed for getting the email message "as Unicode text." A few options are:
- Serializing with
policy=email.policy.default.clone(utf8=True, max_line_length=0, cte_type="8bit"). This avoids most 7-bit encoding (though would still use rfc2231 for attachment filenames). But it would result in very long (unwrapped) lines in message bodies. (Setting policy.max_line_length to anything other than 0 would use base64 or quoted-printable when wrapping non-ASCII text parts, which defeats the purpose.)
- Not serializing the message with
as_bytes(), but instead walking the Python EmailMessage and writing each part as Unicode text. This would guarantee no 7-bit encodings anywhere, and is probably the most flexible (if a bit more work).
In either case, we might want some sort of wrapping for the console. That could be something like textwrap.wrap() or just a hard wrap at 79 chars. Maybe also a separate wrap or max_line_length option to control this.
(Incidentally, I'd originally wanted to handle this as a new policy option, allowing any email.policy.Policy object for serialization. Unfortunately, that alone isn't sufficient for the console backend, if we want to wrap text bodies in the output.)
Code of Conduct
Feature Description
Add an option to Django's console and file EmailBackends to display non-ASCII characters as Unicode (utf-8), rather than the various 7-bit encodings used for SMTP transmission.
Problem
Django's console and filebased EmailBackends output email messages exactly as they would be passed to an SMTP server. That's helpful for debugging SMTP, but not so helpful if you just want to see the content being emailed. And it can be confusing if you aren't familiar with the variety of different encodings needed to represent non-ASCII characters for 7-bit SMTP transmission.
For example, the console EmailBackend might show this for a password reset email. Notice the subject header and message body:
In many cases, it would be more useful to show the original, unencoded Unicode text:
Request or proposal
proposal
Additional Details
See (e.g.,) this forum topic. The developer assumed (reasonably, imho) that the base64-encoded message body echoed to the console was a bug.
With the console backend becoming the default for new projects in the 6.1 settings template, we're likely to start seeing similar reports more often.
Implementation Suggestions
[Edit: see updated proposal in a later comment.]
We could add a
decodeboolean option to the console and filebased backends:When
decodeis True, we'd change the message serialization inwrite_message()so the original, unencoded text content would be written to the console or file (as Unicode text). I think it would also be good to update the new-project settings template to include thedecodeoption as shown above.Some experimentation would be needed for getting the email message "as Unicode text." A few options are:
policy=email.policy.default.clone(utf8=True, max_line_length=0, cte_type="8bit"). This avoids most 7-bit encoding (though would still use rfc2231 for attachment filenames). But it would result in very long (unwrapped) lines in message bodies. (Settingpolicy.max_line_lengthto anything other than 0 would use base64 or quoted-printable when wrapping non-ASCII text parts, which defeats the purpose.)as_bytes(), but instead walking the PythonEmailMessageand writing each part as Unicode text. This would guarantee no 7-bit encodings anywhere, and is probably the most flexible (if a bit more work).In either case, we might want some sort of wrapping for the console. That could be something like
textwrap.wrap()or just a hard wrap at 79 chars. Maybe also a separatewrapormax_line_lengthoption to control this.(Incidentally, I'd originally wanted to handle this as a new
policyoption, allowing anyemail.policy.Policyobject for serialization. Unfortunately, that alone isn't sufficient for the console backend, if we want to wrap text bodies in the output.)