summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPraful Gulani <prafulgulani555@gmail.com>2026-02-12 20:03:25 +0530
committerJacob Walls <jacobtylerwalls@gmail.com>2026-03-16 12:51:58 -0400
commit2333d56696141303000986a16553205ece993c67 (patch)
tree16ec0e70baa0beee82dab88bddf264eaac8ce91e
parent455e787b9cc8bd3342f86ddcf8ef4103fd811bb5 (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--AUTHORS1
-rw-r--r--django/core/mail/__init__.py27
-rw-r--r--django/core/mail/message.py7
-rw-r--r--django/utils/log.py2
-rw-r--r--docs/releases/6.1.txt4
-rw-r--r--docs/topics/email.txt28
-rw-r--r--tests/mail/tests.py117
7 files changed, 177 insertions, 9 deletions
diff --git a/AUTHORS b/AUTHORS
index c480402993..9379176a4c 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -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",
)