django / django/new-features

Console EmailBackend option to show developer-readable email messages

Open
#170 7 comments 7 reactions 0 assignees View on GitHub
Django Core Email
Dominant language
No language data
Stars
188
Forks
7
PR merge metrics
No merged PRs in 30d

Description

### Code of Conduct

- [x] I agree to follow Django's 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:

```text
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:

```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](https://forum.djangoproject.com/t/i-have-bug-on-reset-password-link/45203). 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](#issuecomment-4699784578) in a later comment.]

We could add a `decode` boolean option to the console and filebased backends:

```python
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`](https://docs.python.org/3/library/email.policy.html#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.)

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.