diff options
| author | Praful Gulani <prafulgulani555@gmail.com> | 2026-02-12 20:03:25 +0530 |
|---|---|---|
| committer | Jacob Walls <jacobtylerwalls@gmail.com> | 2026-03-16 12:51:58 -0400 |
| commit | 2333d56696141303000986a16553205ece993c67 (patch) | |
| tree | 16ec0e70baa0beee82dab88bddf264eaac8ce91e | |
| parent | 455e787b9cc8bd3342f86ddcf8ef4103fd811bb5 (diff) | |
Fixed #36894 -- Added TypeError for conflicting arguments in mail APIs.
A TypeError is now raised if fail_silently=True, auth_user, or auth_password
are provided along a connection.
Updated AdminEmailHandler in django.utils.log to remove redundant
fail_silently=True.
Thanks Mike Edmunds for the report and Jacob Tyler Walls for the review.
| -rw-r--r-- | AUTHORS | 1 | ||||
| -rw-r--r-- | django/core/mail/__init__.py | 27 | ||||
| -rw-r--r-- | django/core/mail/message.py | 7 | ||||
| -rw-r--r-- | django/utils/log.py | 2 | ||||
| -rw-r--r-- | docs/releases/6.1.txt | 4 | ||||
| -rw-r--r-- | docs/topics/email.txt | 28 | ||||
| -rw-r--r-- | tests/mail/tests.py | 117 |
7 files changed, 177 insertions, 9 deletions
@@ -865,6 +865,7 @@ answer newbie questions, and generally made Django that much better: plisk polpak@yahoo.com pradeep.gowda@gmail.com + Praful Gulani <https://github.com/prafulgulani> Prashant Pandey <https://prashantpandey9.in> Preston Holmes <preston@ptone.com> Preston Timmons <prestontimmons@gmail.com> diff --git a/django/core/mail/__init__.py b/django/core/mail/__init__.py index 4d7f8bf1d9..6a0baa48ed 100644 --- a/django/core/mail/__init__.py +++ b/django/core/mail/__init__.py @@ -94,6 +94,17 @@ def send_mail( Note: The API for this method is frozen. New code wanting to extend the functionality should use the EmailMessage class directly. """ + if connection is not None: + if fail_silently: + raise TypeError( + "fail_silently cannot be used with a connection. " + "Pass fail_silently to get_connection() instead." + ) + if auth_user is not None or auth_password is not None: + raise TypeError( + "auth_user and auth_password cannot be used with a connection. " + "Pass auth_user and auth_password to get_connection() instead." + ) connection = connection or get_connection( username=auth_user, password=auth_password, @@ -137,6 +148,17 @@ def send_mass_mail( Note: The API for this method is frozen. New code wanting to extend the functionality should use the EmailMessage class directly. """ + if connection is not None: + if fail_silently: + raise TypeError( + "fail_silently cannot be used with a connection. " + "Pass fail_silently to get_connection() instead." + ) + if auth_user is not None or auth_password is not None: + raise TypeError( + "auth_user and auth_password cannot be used with a connection. " + "Pass auth_user and auth_password to get_connection() instead." + ) connection = connection or get_connection( username=auth_user, password=auth_password, @@ -158,6 +180,11 @@ def _send_server_message( fail_silently=False, connection=None, ): + if connection is not None and fail_silently: + raise TypeError( + "fail_silently cannot be used with a connection. " + "Pass fail_silently to get_connection() instead." + ) recipients = getattr(settings, setting_name) if not recipients: return diff --git a/django/core/mail/message.py b/django/core/mail/message.py index 66d5efeb63..6eb85c6a2a 100644 --- a/django/core/mail/message.py +++ b/django/core/mail/message.py @@ -355,6 +355,13 @@ class EmailMessage: # Don't bother creating the network connection if there's nobody to # send to. return 0 + + if fail_silently and self.connection: + raise TypeError( + "fail_silently cannot be used with a connection. " + "Pass fail_silently to get_connection() instead." + ) + return self.get_connection(fail_silently).send_messages([self]) def attach(self, filename=None, content=None, mimetype=None): diff --git a/django/utils/log.py b/django/utils/log.py index d4e96a9816..9a3a7d9f62 100644 --- a/django/utils/log.py +++ b/django/utils/log.py @@ -132,7 +132,7 @@ class AdminEmailHandler(logging.Handler): reporter.get_traceback_text(), ) html_message = reporter.get_traceback_html() if self.include_html else None - self.send_mail(subject, message, fail_silently=True, html_message=html_message) + self.send_mail(subject, message, html_message=html_message) def send_mail(self, subject, message, *args, **kwargs): mail.mail_admins( diff --git a/docs/releases/6.1.txt b/docs/releases/6.1.txt index 67891c5bf7..6b18331a1b 100644 --- a/docs/releases/6.1.txt +++ b/docs/releases/6.1.txt @@ -457,6 +457,10 @@ short-term maintenance releases. Django 6.1 supports MariaDB 10.11 and higher. Miscellaneous ------------- +* Providing ``fail_silently=True``, ``auth_user``, or ``auth_password`` to mail + sending functions (such as :func:`~django.core.mail.send_mail`) while also + providing a ``connection`` now raises a ``TypeError``. + * :class:`~django.contrib.contenttypes.fields.GenericForeignKey` now uses a separate descriptor class: the private ``GenericForeignKeyDescriptor``. diff --git a/docs/topics/email.txt b/docs/topics/email.txt index 6a32a0728e..c10aac2f80 100644 --- a/docs/topics/email.txt +++ b/docs/topics/email.txt @@ -120,6 +120,12 @@ can be ``0`` or ``1`` since it can only send one message). Passing ``fail_silently`` and later parameters as positional arguments is deprecated. +.. versionchanged:: 6.1 + + Older versions ignored ``fail_silently=True``, ``auth_user``, + and ``auth_password`` when a ``connection`` was also provided. + This now raises a ``TypeError``. + ``send_mass_mail()`` ==================== @@ -164,6 +170,13 @@ The return value will be the number of successfully delivered messages. Passing ``fail_silently`` and later parameters as positional arguments is deprecated. + +.. versionchanged:: 6.1 + + Older versions ignored ``fail_silently=True``, ``auth_user``, + and ``auth_password`` when a ``connection`` was also provided. + This now raises a ``TypeError``. + ``send_mass_mail()`` vs. ``send_mail()`` ---------------------------------------- @@ -198,6 +211,11 @@ If ``html_message`` is provided, the resulting email will be a Passing ``fail_silently`` and later parameters as positional arguments is deprecated. +.. versionchanged:: 6.1 + + Older versions ignored ``fail_silently=True`` when a ``connection`` + was also provided. This now raises a ``TypeError``. + ``mail_managers()`` =================== @@ -212,6 +230,11 @@ setting. Passing ``fail_silently`` and later parameters as positional arguments is deprecated. +.. versionchanged:: 6.1 + + Older versions ignored ``fail_silently=True`` when a ``connection`` + was also provided. This now raises a ``TypeError``. + Examples ======== @@ -403,6 +426,11 @@ email backend API :ref:`provides an alternative an exception. It will return ``1`` if the message was sent successfully, otherwise ``0``. + .. versionchanged:: 6.1 + + Older versions ignored ``fail_silently=True`` when a ``connection`` + was also provided. This now raises a ``TypeError``. + .. method:: message(policy=email.policy.default) Constructs and returns a Python :class:`email.message.EmailMessage` diff --git a/tests/mail/tests.py b/tests/mail/tests.py index 851d1c371c..3ba3b9d062 100644 --- a/tests/mail/tests.py +++ b/tests/mail/tests.py @@ -1999,6 +1999,107 @@ class MailTests(MailTestsMixin, SimpleTestCase): message.as_string(policy=policy.compat32), ) + def test_send_mail_fail_silently_conflict(self): + msg = ( + "fail_silently cannot be used with a connection. " + "Pass fail_silently to get_connection() instead." + ) + with self.assertRaisesMessage(TypeError, msg): + mail.send_mail( + "Subject", + "Body", + "from@example.com", + ["to@example.com"], + fail_silently=True, + connection=mail.get_connection(), + ) + + def test_send_mail_auth_conflict(self): + msg = ( + "auth_user and auth_password cannot be used with a connection. " + "Pass auth_user and auth_password to get_connection() instead." + ) + for param in ["auth_user", "auth_password"]: + with ( + self.subTest(param=param), + self.assertRaisesMessage(TypeError, msg), + ): + mail.send_mail( + "subject", + "body", + "from@example.com", + ["to@example.com"], + **{param: "value"}, + connection=mail.get_connection(), + ) + + def test_email_message_send_fail_silently_conflict(self): + email = mail.EmailMessage( + "Subject", + "Body", + "from@example.com", + ["to@example.com"], + connection=mail.get_connection(), + ) + msg = ( + "fail_silently cannot be used with a connection. " + "Pass fail_silently to get_connection() instead." + ) + with self.assertRaisesMessage(TypeError, msg): + email.send(fail_silently=True) + + def test_send_mass_mail_fail_silently_conflict(self): + datatuple = (("Subject", "Message", "from@example.com", ["to@example.com"]),) + msg = ( + "fail_silently cannot be used with a connection. " + "Pass fail_silently to get_connection() instead." + ) + with self.assertRaisesMessage(TypeError, msg): + mail.send_mass_mail( + datatuple, fail_silently=True, connection=mail.get_connection() + ) + + def test_send_mass_mail_auth_conflict(self): + datatuple = (("Subject", "Message", "from@example.com", ["to@example.com"]),) + msg = ( + "auth_user and auth_password cannot be used with a connection. " + "Pass auth_user and auth_password to get_connection() instead." + ) + for param in ["auth_user", "auth_password"]: + with ( + self.subTest(param=param), + self.assertRaisesMessage(TypeError, msg), + ): + mail.send_mass_mail( + datatuple, **{param: "value"}, connection=mail.get_connection() + ) + + def test_mail_admins_fail_silently_conflict(self): + msg = ( + "fail_silently cannot be used with a connection. " + "Pass fail_silently to get_connection() instead." + ) + with self.assertRaisesMessage(TypeError, msg): + mail.mail_admins( + "Subject", + "Message", + fail_silently=True, + connection=mail.get_connection(), + ) + + def test_mail_managers_fail_silently_conflict(self): + msg = ( + "fail_silently cannot be used with a connection. " + "Pass fail_silently to get_connection() instead." + ) + with self.assertRaisesMessage(TypeError, msg): + mail.mail_managers( + "Subject", + "Message", + fail_silently=True, + connection=mail.get_connection(), + ) + # RemovedInDjango70Warning. class MailDeprecatedPositionalArgsTests(SimpleTestCase): @@ -2029,9 +2130,9 @@ class MailDeprecatedPositionalArgsTests(SimpleTestCase): "from@example.com", ["to@example.com"], # Deprecated positional args: - True, - "username", - "password", + None, + None, + None, mail.get_connection(), "html message", ) @@ -2044,9 +2145,9 @@ class MailDeprecatedPositionalArgsTests(SimpleTestCase): send_mass_mail( [], # Deprecated positional args: - True, - "username", - "password", + None, + None, + None, mail.get_connection(), ) @@ -2058,7 +2159,7 @@ class MailDeprecatedPositionalArgsTests(SimpleTestCase): "subject", "message", # Deprecated positional args: - True, + None, mail.get_connection(), "html message", ) @@ -2071,7 +2172,7 @@ class MailDeprecatedPositionalArgsTests(SimpleTestCase): "subject", "message", # Deprecated positional args: - True, + None, mail.get_connection(), "html message", ) |
