mirror of
https://github.com/django/django.git
synced 2025-08-21 17:29:13 +00:00
Fixed #36163 -- Deprecated most positional arguments in django.core.mail.
In public mail APIs, changed less frequently used parameters from keyword-or-positional to keyword-only, emitting a warning during the required deprecation period.
This commit is contained in:
parent
5289ce65b9
commit
fc793fc303
@ -24,7 +24,7 @@ from django.core.mail.message import (
|
||||
make_msgid,
|
||||
)
|
||||
from django.core.mail.utils import DNS_NAME, CachedDnsName
|
||||
from django.utils.deprecation import RemovedInDjango70Warning
|
||||
from django.utils.deprecation import RemovedInDjango70Warning, deprecate_posargs
|
||||
from django.utils.functional import Promise
|
||||
from django.utils.module_loading import import_string
|
||||
|
||||
@ -49,7 +49,8 @@ __all__ = [
|
||||
]
|
||||
|
||||
|
||||
def get_connection(backend=None, fail_silently=False, **kwds):
|
||||
@deprecate_posargs(RemovedInDjango70Warning, ["fail_silently"])
|
||||
def get_connection(backend=None, *, fail_silently=False, **kwds):
|
||||
"""Load an email backend and return an instance of it.
|
||||
|
||||
If backend is None (default), use settings.EMAIL_BACKEND.
|
||||
@ -61,11 +62,22 @@ def get_connection(backend=None, fail_silently=False, **kwds):
|
||||
return klass(fail_silently=fail_silently, **kwds)
|
||||
|
||||
|
||||
@deprecate_posargs(
|
||||
RemovedInDjango70Warning,
|
||||
[
|
||||
"fail_silently",
|
||||
"auth_user",
|
||||
"auth_password",
|
||||
"connection",
|
||||
"html_message",
|
||||
],
|
||||
)
|
||||
def send_mail(
|
||||
subject,
|
||||
message,
|
||||
from_email,
|
||||
recipient_list,
|
||||
*,
|
||||
fail_silently=False,
|
||||
auth_user=None,
|
||||
auth_password=None,
|
||||
@ -97,8 +109,22 @@ def send_mail(
|
||||
return mail.send()
|
||||
|
||||
|
||||
@deprecate_posargs(
|
||||
RemovedInDjango70Warning,
|
||||
[
|
||||
"fail_silently",
|
||||
"auth_user",
|
||||
"auth_password",
|
||||
"connection",
|
||||
],
|
||||
)
|
||||
def send_mass_mail(
|
||||
datatuple, fail_silently=False, auth_user=None, auth_password=None, connection=None
|
||||
datatuple,
|
||||
*,
|
||||
fail_silently=False,
|
||||
auth_user=None,
|
||||
auth_password=None,
|
||||
connection=None,
|
||||
):
|
||||
"""
|
||||
Given a datatuple of (subject, message, from_email, recipient_list), send
|
||||
@ -166,8 +192,11 @@ def _send_server_message(
|
||||
mail.send(fail_silently=fail_silently)
|
||||
|
||||
|
||||
@deprecate_posargs(
|
||||
RemovedInDjango70Warning, ["fail_silently", "connection", "html_message"]
|
||||
)
|
||||
def mail_admins(
|
||||
subject, message, fail_silently=False, connection=None, html_message=None
|
||||
subject, message, *, fail_silently=False, connection=None, html_message=None
|
||||
):
|
||||
"""Send a message to the admins, as defined by the ADMINS setting."""
|
||||
_send_server_message(
|
||||
@ -180,8 +209,11 @@ def mail_admins(
|
||||
)
|
||||
|
||||
|
||||
@deprecate_posargs(
|
||||
RemovedInDjango70Warning, ["fail_silently", "connection", "html_message"]
|
||||
)
|
||||
def mail_managers(
|
||||
subject, message, fail_silently=False, connection=None, html_message=None
|
||||
subject, message, *, fail_silently=False, connection=None, html_message=None
|
||||
):
|
||||
"""Send a message to the managers, as defined by the MANAGERS setting."""
|
||||
_send_server_message(
|
||||
|
@ -17,6 +17,7 @@ from pathlib import Path
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.mail.utils import DNS_NAME
|
||||
from django.utils.deprecation import RemovedInDjango70Warning, deprecate_posargs
|
||||
from django.utils.encoding import force_bytes, force_str, punycode
|
||||
|
||||
# Don't BASE64-encode UTF-8 messages so that we avoid unwanted attention from
|
||||
@ -202,12 +203,24 @@ class EmailMessage:
|
||||
mixed_subtype = "mixed"
|
||||
encoding = None # None => use settings default
|
||||
|
||||
@deprecate_posargs(
|
||||
RemovedInDjango70Warning,
|
||||
[
|
||||
"bcc",
|
||||
"connection",
|
||||
"attachments",
|
||||
"headers",
|
||||
"cc",
|
||||
"reply_to",
|
||||
],
|
||||
)
|
||||
def __init__(
|
||||
self,
|
||||
subject="",
|
||||
body="",
|
||||
from_email=None,
|
||||
to=None,
|
||||
*,
|
||||
bcc=None,
|
||||
connection=None,
|
||||
attachments=None,
|
||||
@ -455,12 +468,25 @@ class EmailMultiAlternatives(EmailMessage):
|
||||
|
||||
alternative_subtype = "alternative"
|
||||
|
||||
@deprecate_posargs(
|
||||
RemovedInDjango70Warning,
|
||||
[
|
||||
"bcc",
|
||||
"connection",
|
||||
"attachments",
|
||||
"headers",
|
||||
"alternatives",
|
||||
"cc",
|
||||
"reply_to",
|
||||
],
|
||||
)
|
||||
def __init__(
|
||||
self,
|
||||
subject="",
|
||||
body="",
|
||||
from_email=None,
|
||||
to=None,
|
||||
*,
|
||||
bcc=None,
|
||||
connection=None,
|
||||
attachments=None,
|
||||
@ -478,12 +504,12 @@ class EmailMultiAlternatives(EmailMessage):
|
||||
body,
|
||||
from_email,
|
||||
to,
|
||||
bcc,
|
||||
connection,
|
||||
attachments,
|
||||
headers,
|
||||
cc,
|
||||
reply_to,
|
||||
bcc=bcc,
|
||||
connection=connection,
|
||||
attachments=attachments,
|
||||
headers=headers,
|
||||
cc=cc,
|
||||
reply_to=reply_to,
|
||||
)
|
||||
self.alternatives = [
|
||||
EmailAlternative(*alternative) for alternative in (alternatives or [])
|
||||
|
@ -38,6 +38,9 @@ details on these changes.
|
||||
argument of ``django.core.paginator.Paginator`` and
|
||||
``django.core.paginator.AsyncPaginator`` will no longer be allowed.
|
||||
|
||||
* The :mod:`django.core.mail` APIs will no longer accept certain parameters as
|
||||
positional arguments. These must be passed as keyword arguments instead.
|
||||
|
||||
.. _deprecation-removed-in-6.1:
|
||||
|
||||
6.1
|
||||
|
@ -405,6 +405,26 @@ Miscellaneous
|
||||
Features deprecated in 6.0
|
||||
==========================
|
||||
|
||||
Positional arguments in ``django.core.mail`` APIs
|
||||
-------------------------------------------------
|
||||
|
||||
.. currentmodule:: django.core.mail
|
||||
|
||||
:mod:`django.core.mail` APIs now require keyword arguments for less commonly
|
||||
used parameters. Using positional arguments for these now emits a deprecation
|
||||
warning and will raise a :exc:`TypeError` when the deprecation period ends.
|
||||
|
||||
* All *optional* parameters (``fail_silently`` and later) must be passed as
|
||||
keyword arguments to :func:`get_connection`, :func:`mail_admins`,
|
||||
:func:`mail_managers`, :func:`send_mail`, and :func:`send_mass_mail`.
|
||||
|
||||
* All parameters must be passed as keyword arguments when creating an
|
||||
:class:`EmailMessage` or :class:`EmailMultiAlternatives` instance, except for
|
||||
the first four (``subject``, ``body``, ``from_email``, and ``to``), which may
|
||||
still be passed either as positional or keyword arguments.
|
||||
|
||||
.. currentmodule:: None
|
||||
|
||||
Miscellaneous
|
||||
-------------
|
||||
|
||||
|
@ -76,7 +76,7 @@ a secure connection is used.
|
||||
``send_mail()``
|
||||
===============
|
||||
|
||||
.. function:: send_mail(subject, message, from_email, recipient_list, fail_silently=False, auth_user=None, auth_password=None, connection=None, html_message=None)
|
||||
.. function:: send_mail(subject, message, from_email, recipient_list, *, fail_silently=False, auth_user=None, auth_password=None, connection=None, html_message=None)
|
||||
|
||||
In most cases, you can send email using ``django.core.mail.send_mail()``.
|
||||
|
||||
@ -90,6 +90,10 @@ are required.
|
||||
* ``recipient_list``: A list of strings, each an email address. Each
|
||||
member of ``recipient_list`` will see the other recipients in the "To:"
|
||||
field of the email message.
|
||||
|
||||
The following parameters are optional, and must be given as keyword arguments
|
||||
if used.
|
||||
|
||||
* ``fail_silently``: A boolean. When it's ``False``, ``send_mail()`` will raise
|
||||
an :exc:`smtplib.SMTPException` if an error occurs. See the :mod:`smtplib`
|
||||
docs for a list of possible exceptions, all of which are subclasses of
|
||||
@ -112,10 +116,15 @@ are required.
|
||||
The return value will be the number of successfully delivered messages (which
|
||||
can be ``0`` or ``1`` since it can only send one message).
|
||||
|
||||
.. deprecated:: 6.0
|
||||
|
||||
Passing ``fail_silently`` and later parameters as positional arguments is
|
||||
deprecated.
|
||||
|
||||
``send_mass_mail()``
|
||||
====================
|
||||
|
||||
.. function:: send_mass_mail(datatuple, fail_silently=False, auth_user=None, auth_password=None, connection=None)
|
||||
.. function:: send_mass_mail(datatuple, *, fail_silently=False, auth_user=None, auth_password=None, connection=None)
|
||||
|
||||
``django.core.mail.send_mass_mail()`` is intended to handle mass emailing.
|
||||
|
||||
@ -123,8 +132,9 @@ can be ``0`` or ``1`` since it can only send one message).
|
||||
|
||||
(subject, message, from_email, recipient_list)
|
||||
|
||||
``fail_silently``, ``auth_user`` and ``auth_password`` have the same functions
|
||||
as in :meth:`~django.core.mail.send_mail()`.
|
||||
``fail_silently``, ``auth_user``, ``auth_password`` and ``connection`` have the
|
||||
same functions as in :meth:`~django.core.mail.send_mail()`. They must be given
|
||||
as keyword arguments if used.
|
||||
|
||||
Each separate element of ``datatuple`` results in a separate email message.
|
||||
As in :meth:`~django.core.mail.send_mail()`, recipients in the same
|
||||
@ -151,6 +161,11 @@ mail server would be opened::
|
||||
|
||||
The return value will be the number of successfully delivered messages.
|
||||
|
||||
.. deprecated:: 6.0
|
||||
|
||||
Passing ``fail_silently`` and later parameters as positional arguments is
|
||||
deprecated.
|
||||
|
||||
``send_mass_mail()`` vs. ``send_mail()``
|
||||
----------------------------------------
|
||||
|
||||
@ -164,7 +179,7 @@ a single connection for all of its messages. This makes
|
||||
``mail_admins()``
|
||||
=================
|
||||
|
||||
.. function:: mail_admins(subject, message, fail_silently=False, connection=None, html_message=None)
|
||||
.. function:: mail_admins(subject, message, *, fail_silently=False, connection=None, html_message=None)
|
||||
|
||||
``django.core.mail.mail_admins()`` is a shortcut for sending an email to the
|
||||
site admins, as defined in the :setting:`ADMINS` setting.
|
||||
@ -182,15 +197,25 @@ If ``html_message`` is provided, the resulting email will be a
|
||||
:mimetype:`text/plain` content type and ``html_message`` as the
|
||||
:mimetype:`text/html` content type.
|
||||
|
||||
.. deprecated:: 6.0
|
||||
|
||||
Passing ``fail_silently`` and later parameters as positional arguments is
|
||||
deprecated.
|
||||
|
||||
``mail_managers()``
|
||||
===================
|
||||
|
||||
.. function:: mail_managers(subject, message, fail_silently=False, connection=None, html_message=None)
|
||||
.. function:: mail_managers(subject, message, *, fail_silently=False, connection=None, html_message=None)
|
||||
|
||||
``django.core.mail.mail_managers()`` is just like ``mail_admins()``, except it
|
||||
sends an email to the site managers, as defined in the :setting:`MANAGERS`
|
||||
setting.
|
||||
|
||||
.. deprecated:: 6.0
|
||||
|
||||
Passing ``fail_silently`` and later parameters as positional arguments is
|
||||
deprecated.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
@ -294,9 +319,11 @@ email backend API :ref:`provides an alternative
|
||||
.. class:: EmailMessage
|
||||
|
||||
The :class:`~django.core.mail.EmailMessage` class is initialized with the
|
||||
following parameters (in the given order, if positional arguments are used).
|
||||
All parameters are optional and can be set at any time prior to calling the
|
||||
``send()`` method.
|
||||
following parameters. All parameters are optional and can be set at any time
|
||||
prior to calling the ``send()`` method.
|
||||
|
||||
The first four parameters can be passed as positional or keyword arguments,
|
||||
but must be in the given order if positional arguments are used:
|
||||
|
||||
* ``subject``: The subject line of the email.
|
||||
|
||||
@ -308,6 +335,8 @@ All parameters are optional and can be set at any time prior to calling the
|
||||
|
||||
* ``to``: A list or tuple of recipient addresses.
|
||||
|
||||
The following parameters must be given as keyword arguments if used:
|
||||
|
||||
* ``bcc``: A list or tuple of addresses used in the "Bcc" header when
|
||||
sending the email.
|
||||
|
||||
@ -338,6 +367,11 @@ All parameters are optional and can be set at any time prior to calling the
|
||||
* ``reply_to``: A list or tuple of recipient addresses used in the "Reply-To"
|
||||
header when sending the email.
|
||||
|
||||
.. deprecated:: 6.0
|
||||
|
||||
Passing all except the first four parameters as positional arguments is
|
||||
deprecated.
|
||||
|
||||
For example::
|
||||
|
||||
from django.core.mail import EmailMessage
|
||||
@ -347,7 +381,7 @@ For example::
|
||||
"Body goes here",
|
||||
"from@example.com",
|
||||
["to1@example.com", "to2@example.com"],
|
||||
["bcc@example.com"],
|
||||
bcc=["bcc@example.com"],
|
||||
reply_to=["another@example.com"],
|
||||
headers={"Message-ID": "foo"},
|
||||
)
|
||||
@ -582,15 +616,15 @@ instance of the email backend that you can use.
|
||||
|
||||
.. currentmodule:: django.core.mail
|
||||
|
||||
.. function:: get_connection(backend=None, fail_silently=False, **kwargs)
|
||||
.. function:: get_connection(backend=None, *, fail_silently=False, **kwargs)
|
||||
|
||||
By default, a call to ``get_connection()`` will return an instance of the
|
||||
email backend specified in :setting:`EMAIL_BACKEND`. If you specify the
|
||||
``backend`` argument, an instance of that backend will be instantiated.
|
||||
|
||||
The ``fail_silently`` argument controls how the backend should handle errors.
|
||||
If ``fail_silently`` is True, exceptions during the email sending process
|
||||
will be silently ignored.
|
||||
The keyword-only ``fail_silently`` argument controls how the backend should
|
||||
handle errors. If ``fail_silently`` is True, exceptions during the email
|
||||
sending process will be silently ignored.
|
||||
|
||||
All other keyword arguments are passed directly to the constructor of the
|
||||
email backend.
|
||||
@ -600,6 +634,10 @@ SMTP backend (which is the default), these backends are only useful during
|
||||
testing and development. If you have special email sending requirements, you
|
||||
can :ref:`write your own email backend <topic-custom-email-backend>`.
|
||||
|
||||
.. deprecated:: 6.0
|
||||
|
||||
Passing ``fail_silently`` as positional argument is deprecated.
|
||||
|
||||
.. _topic-email-smtp-backend:
|
||||
|
||||
SMTP backend
|
||||
|
@ -1266,7 +1266,7 @@ class PasswordResetFormTest(TestDataMixin, TestCase):
|
||||
"Sorry to hear you forgot your password.",
|
||||
None,
|
||||
[to_email],
|
||||
["site_monitor@example.com"],
|
||||
bcc=["site_monitor@example.com"],
|
||||
headers={"Reply-To": "webmaster@example.com"},
|
||||
alternatives=[
|
||||
("Really sorry to hear you forgot your password.", "text/html")
|
||||
|
@ -1751,13 +1751,13 @@ class MailTests(MailTestsMixin, SimpleTestCase):
|
||||
"body\n",
|
||||
"from@example.com",
|
||||
["to@example.com"],
|
||||
["bcc@example.com"],
|
||||
connection,
|
||||
[EmailAttachment("file.txt", "attachment\n", "text/plain")],
|
||||
{"X-Header": "custom header"},
|
||||
["cc@example.com"],
|
||||
["reply-to@example.com"],
|
||||
# (New options can be added below here, ideally as keyword-only args.)
|
||||
# (New options can be added below here as keyword-only args.)
|
||||
bcc=["bcc@example.com"],
|
||||
connection=connection,
|
||||
attachments=[EmailAttachment("file.txt", "attachment\n", "text/plain")],
|
||||
headers={"X-Header": "custom header"},
|
||||
cc=["cc@example.com"],
|
||||
reply_to=["reply-to@example.com"],
|
||||
)
|
||||
|
||||
message = email.message()
|
||||
@ -1791,12 +1791,14 @@ class MailTests(MailTestsMixin, SimpleTestCase):
|
||||
"original body\n",
|
||||
"original-from@example.com",
|
||||
["original-to@example.com"],
|
||||
["original-bcc@example.com"],
|
||||
original_connection,
|
||||
[EmailAttachment("original.txt", "original attachment\n", "text/plain")],
|
||||
{"X-Header": "original header"},
|
||||
["original-cc@example.com"],
|
||||
["original-reply-to@example.com"],
|
||||
bcc=["original-bcc@example.com"],
|
||||
connection=original_connection,
|
||||
attachments=[
|
||||
EmailAttachment("original.txt", "original attachment\n", "text/plain")
|
||||
],
|
||||
headers={"X-Header": "original header"},
|
||||
cc=["original-cc@example.com"],
|
||||
reply_to=["original-reply-to@example.com"],
|
||||
)
|
||||
email.subject = "new subject"
|
||||
email.body = "new body\n"
|
||||
@ -1837,6 +1839,123 @@ class MailTests(MailTestsMixin, SimpleTestCase):
|
||||
self.assertNotIn("original", message.as_string())
|
||||
|
||||
|
||||
# RemovedInDjango70Warning.
|
||||
class MailDeprecatedPositionalArgsTests(SimpleTestCase):
|
||||
|
||||
def assertDeprecatedIn70(self, params, name):
|
||||
return self.assertWarnsMessage(
|
||||
RemovedInDjango70Warning,
|
||||
f"Passing positional argument(s) {params} to {name}() is deprecated.",
|
||||
)
|
||||
|
||||
def test_get_connection(self):
|
||||
with self.assertDeprecatedIn70("'fail_silently'", "get_connection"):
|
||||
mail.get_connection(
|
||||
"django.core.mail.backends.dummy.EmailBackend",
|
||||
# Deprecated positional arg:
|
||||
True,
|
||||
)
|
||||
|
||||
def test_send_mail(self):
|
||||
with self.assertDeprecatedIn70(
|
||||
"'fail_silently', 'auth_user', 'auth_password', 'connection', "
|
||||
"'html_message'",
|
||||
"send_mail",
|
||||
):
|
||||
send_mail(
|
||||
"subject",
|
||||
"message",
|
||||
"from@example.com",
|
||||
["to@example.com"],
|
||||
# Deprecated positional args:
|
||||
True,
|
||||
"username",
|
||||
"password",
|
||||
mail.get_connection(),
|
||||
"html message",
|
||||
)
|
||||
|
||||
def test_send_mass_mail(self):
|
||||
with self.assertDeprecatedIn70(
|
||||
"'fail_silently', 'auth_user', 'auth_password', 'connection'",
|
||||
"send_mass_mail",
|
||||
):
|
||||
send_mass_mail(
|
||||
[],
|
||||
# Deprecated positional args:
|
||||
True,
|
||||
"username",
|
||||
"password",
|
||||
mail.get_connection(),
|
||||
)
|
||||
|
||||
def test_mail_admins(self):
|
||||
with self.assertDeprecatedIn70(
|
||||
"'fail_silently', 'connection', 'html_message'", "mail_admins"
|
||||
):
|
||||
mail_admins(
|
||||
"subject",
|
||||
"message",
|
||||
# Deprecated positional args:
|
||||
True,
|
||||
mail.get_connection(),
|
||||
"html message",
|
||||
)
|
||||
|
||||
def test_mail_managers(self):
|
||||
with self.assertDeprecatedIn70(
|
||||
"'fail_silently', 'connection', 'html_message'", "mail_managers"
|
||||
):
|
||||
mail_managers(
|
||||
"subject",
|
||||
"message",
|
||||
# Deprecated positional args:
|
||||
True,
|
||||
mail.get_connection(),
|
||||
"html message",
|
||||
)
|
||||
|
||||
def test_email_message_init(self):
|
||||
with self.assertDeprecatedIn70(
|
||||
"'bcc', 'connection', 'attachments', 'headers', 'cc', 'reply_to'",
|
||||
"EmailMessage",
|
||||
):
|
||||
EmailMessage(
|
||||
"subject",
|
||||
"body\n",
|
||||
"from@example.com",
|
||||
["to@example.com"],
|
||||
# Deprecated positional args:
|
||||
["bcc@example.com"],
|
||||
mail.get_connection(),
|
||||
[EmailAttachment("file.txt", "attachment\n", "text/plain")],
|
||||
{"X-Header": "custom header"},
|
||||
["cc@example.com"],
|
||||
["reply-to@example.com"],
|
||||
)
|
||||
|
||||
def test_email_multi_alternatives_init(self):
|
||||
with self.assertDeprecatedIn70(
|
||||
"'bcc', 'connection', 'attachments', 'headers', 'alternatives', 'cc', "
|
||||
"'reply_to'",
|
||||
"EmailMultiAlternatives",
|
||||
):
|
||||
EmailMultiAlternatives(
|
||||
"subject",
|
||||
"body\n",
|
||||
"from@example.com",
|
||||
["to@example.com"],
|
||||
# Deprecated positional args:
|
||||
["bcc@example.com"],
|
||||
mail.get_connection(),
|
||||
[EmailAttachment("file.txt", "attachment\n", "text/plain")],
|
||||
{"X-Header": "custom header"},
|
||||
[EmailAlternative("html body", "text/html")],
|
||||
["cc@example.com"],
|
||||
["reply-to@example.com"],
|
||||
)
|
||||
|
||||
|
||||
@requires_tz_support
|
||||
class MailTimeZoneTests(MailTestsMixin, SimpleTestCase):
|
||||
@override_settings(
|
||||
|
Loading…
x
Reference in New Issue
Block a user