Skip to content

Commit 0c66e1e

Browse files
authored
Docs: document DEBUG_API_REQUESTS setting
(And add a system check to warn about its use in production deployment.)
1 parent 95080bf commit 0c66e1e

File tree

5 files changed

+63
-2
lines changed

5 files changed

+63
-2
lines changed

anymail/apps.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from django.apps import AppConfig
22
from django.core import checks
33

4-
from .checks import check_deprecated_settings
4+
from .checks import check_deprecated_settings, check_insecure_settings
55

66

77
class AnymailBaseConfig(AppConfig):
@@ -10,3 +10,4 @@ class AnymailBaseConfig(AppConfig):
1010

1111
def ready(self):
1212
checks.register(check_deprecated_settings)
13+
checks.register(check_insecure_settings)

anymail/checks.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from django.conf import settings
22
from django.core import checks
33

4+
from anymail.utils import get_anymail_setting
5+
46

57
def check_deprecated_settings(app_configs, **kwargs):
68
errors = []
@@ -24,3 +26,18 @@ def check_deprecated_settings(app_configs, **kwargs):
2426
))
2527

2628
return errors
29+
30+
31+
def check_insecure_settings(app_configs, **kwargs):
32+
errors = []
33+
34+
# anymail.W002: DEBUG_API_REQUESTS can leak private information
35+
if get_anymail_setting("debug_api_requests", default=False) and not settings.DEBUG:
36+
errors.append(checks.Warning(
37+
"You have enabled the ANYMAIL setting DEBUG_API_REQUESTS, which can "
38+
"leak API keys and other sensitive data into logs or the console.",
39+
hint="You should not use DEBUG_API_REQUESTS in production deployment.",
40+
id="anymail.W002",
41+
))
42+
43+
return errors

docs/help.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,14 @@ often help you pinpoint the problem...
4444
other than Anymail. And you can look through the :setting:`EMAIL_FILE_PATH`
4545
file contents afterward to see if you're generating the email you want.
4646

47+
**Examine the raw API communication**
48+
49+
Sometimes you just want to see exactly what Anymail is telling your ESP to do
50+
and how your ESP is responding. In a dev environment, enable the Anymail setting
51+
:setting:`DEBUG_API_REQUESTS <ANYMAIL_DEBUG_API_REQUESTS>`
52+
to show the raw HTTP requests and responses from (most) ESP APIs. (This is not
53+
recommended in production, as it can leak sensitive data into your logs.)
54+
4755

4856
.. _contact:
4957
.. _support:

docs/installation.rst

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,3 +299,25 @@ For Requests-based Anymail backends, the timeout value used for all API calls to
299299
The default is 30 seconds. You can set to a single float, a 2-tuple of floats for
300300
separate connection and read timeouts, or `None` to disable timeouts (not recommended).
301301
See :ref:`requests:timeouts` in the Requests docs for more information.
302+
303+
304+
.. setting:: ANYMAIL_DEBUG_API_REQUESTS
305+
306+
.. rubric:: DEBUG_API_REQUESTS
307+
308+
.. versionadded:: 4.3
309+
310+
When set to `True`, outputs the raw API communication with the ESP, to assist in
311+
debugging. Each HTTP request and ESP response is dumped to :data:`sys.stdout` once
312+
the response is received.
313+
314+
.. caution::
315+
316+
Do not enable :setting:`!DEBUG_API_REQUESTS` in production deployments. The debug
317+
output will include your API keys, email addresses, and other sensitive data
318+
that you generally don't want to capture in server logs or reveal on the console.
319+
320+
:setting:`!DEBUG_API_REQUESTS` only applies to sending email through Requests-based
321+
Anymail backends. For other backends, there may be similar debugging facilities
322+
available in the ESP's API wrapper package (e.g., ``boto3.set_stream_logger`` for
323+
Amazon SES).

tests/test_checks.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from django.test import SimpleTestCase
33
from django.test.utils import override_settings
44

5-
from anymail.checks import check_deprecated_settings
5+
from anymail.checks import check_deprecated_settings, check_insecure_settings
66

77
from .utils import AnymailTestMixin
88

@@ -25,3 +25,16 @@ def test_anymail_webhook_authorization(self):
2525
hint="You must update your settings.py.",
2626
id="anymail.E001",
2727
)])
28+
29+
30+
class InsecureSettingsTests(SimpleTestCase, AnymailTestMixin):
31+
@override_settings(ANYMAIL={"DEBUG_API_REQUESTS": True})
32+
def test_debug_api_requests_deployed(self):
33+
errors = check_insecure_settings(None)
34+
self.assertEqual(len(errors), 1)
35+
self.assertEqual(errors[0].id, "anymail.W002")
36+
37+
@override_settings(ANYMAIL={"DEBUG_API_REQUESTS": True}, DEBUG=True)
38+
def test_debug_api_requests_debug(self):
39+
errors = check_insecure_settings(None)
40+
self.assertEqual(len(errors), 0) # no warning in DEBUG (non-production) config

0 commit comments

Comments
 (0)