Repository: pypi/warehouse

Issue:
Using undeclared dependency attrs
**Describe the bug**
<!-- A clear and concise description the bug -->

From @di 

Regarding:
https://github.com/pypa/warehouse/blob/b344984ee83126eb6fc541406d1f34719fad8b6b/warehouse/email/services.py#L36

> Currently attrs is not a top-level dependency of Warehouse, it's only available as a sub-dependency of automat. If we truly need to use attrs here, it should be added to https://github.com/pypa/warehouse/blob/master/requirements/main.in and those dependencies should be re-compiled.

(source: https://github.com/pypa/warehouse/pull/7124#discussion_r453729298)

**Expected behavior**
<!-- A clear and concise description of what you expected to happen -->

attrs should be added in main.in OR removed from the codebase.


Discussion:
I've added the "good first issue" label to this issue.

I also said on that comment: 

> However I think I'd prefer to just use a regular class here.
Ah, I didn't know if it applied here too ! :)

Resolving patch:
diff --git a/warehouse/email/__init__.py b/warehouse/email/__init__.py
--- a/warehouse/email/__init__.py
+++ b/warehouse/email/__init__.py
@@ -14,8 +14,6 @@
 
 from email.headerregistry import Address
 
-import attr
-
 from celery.schedules import crontab
 from first import first
 
@@ -69,7 +67,11 @@ def _send_email_to_user(request, user, msg, *, email=None, allow_unverified=Fals
 
     request.task(send_email).delay(
         _compute_recipient(user, email.email),
-        attr.asdict(msg),
+        {
+            "subject": msg.subject,
+            "body_text": msg.body_text,
+            "body_html": msg.body_html,
+        },
         {
             "tag": "account:email:sent",
             "user_id": user.id,
diff --git a/warehouse/email/services.py b/warehouse/email/services.py
--- a/warehouse/email/services.py
+++ b/warehouse/email/services.py
@@ -15,7 +15,6 @@
 from email.utils import parseaddr
 from typing import Optional
 
-import attr
 import premailer
 
 from jinja2.exceptions import TemplateNotFound
@@ -33,12 +32,11 @@ def _format_sender(sitename, sender):
         return str(Address(sitename, addr_spec=sender))
 
 
-@attr.s(auto_attribs=True, frozen=True, slots=True)
 class EmailMessage:
-
-    subject: str
-    body_text: str
-    body_html: Optional[str] = None
+    def __init__(self, subject: str, body_text: str, body_html: Optional[str] = None):
+        self.subject = subject
+        self.body_text = body_text
+        self.body_html = body_html
 
     @classmethod
     def from_template(cls, email_name, context, *, request):


Test patch:
diff --git a/tests/unit/email/test_init.py b/tests/unit/email/test_init.py
--- a/tests/unit/email/test_init.py
+++ b/tests/unit/email/test_init.py
@@ -12,7 +12,6 @@
 
 import datetime
 
-import attr
 import celery.exceptions
 import pretend
 import pytest
@@ -276,7 +275,11 @@ def record_event(self, user_id, tag, ip_address, additional):
             task,
             request,
             "recipient",
-            attr.asdict(msg),
+            {
+                "subject": msg.subject,
+                "body_text": msg.body_text,
+                "body_html": msg.body_html,
+            },
             {
                 "tag": "account:email:sent",
                 "user_id": user_id,
@@ -339,7 +342,11 @@ def retry(exc):
                 task,
                 request,
                 "recipient",
-                attr.asdict(msg),
+                {
+                    "subject": msg.subject,
+                    "body_text": msg.body_text,
+                    "body_html": msg.body_html,
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": user_id,
@@ -455,16 +462,14 @@ def test_send_password_reset_email(
                 "name_value <"
                 + (stub_user.email if email_addr is None else email_addr)
                 + ">",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
-                    )
-                ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
+                    ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": stub_user.id,
@@ -548,16 +553,14 @@ def test_email_verification_email(
         assert send_email.delay.calls == [
             pretend.call(
                 stub_email.email,
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
-                    )
-                ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
+                    ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": stub_user.id,
@@ -621,16 +624,14 @@ def test_password_change_email(self, pyramid_request, pyramid_config, monkeypatc
         assert send_email.delay.calls == [
             pretend.call(
                 f"{stub_user.username} <{stub_user.email}>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
-                    )
-                ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
+                    ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": stub_user.id,
@@ -741,16 +742,14 @@ def test_password_compromised_email_hibp(
         assert send_email.delay.calls == [
             pretend.call(
                 f"{stub_user.username} <{stub_user.email}>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
-                    )
-                ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
+                    ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": stub_user.id,
@@ -814,16 +813,14 @@ def test_password_compromised_email(
         assert send_email.delay.calls == [
             pretend.call(
                 f"{stub_user.username} <{stub_user.email}>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
-                    )
-                ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
+                    ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": stub_user.id,
@@ -888,16 +885,14 @@ def test_account_deletion_email(self, pyramid_request, pyramid_config, monkeypat
         assert send_email.delay.calls == [
             pretend.call(
                 f"{stub_user.username} <{stub_user.email}>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
-                    )
-                ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
+                    ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": stub_user.id,
@@ -1016,16 +1011,14 @@ def test_primary_email_change_email(
         assert send_email.delay.calls == [
             pretend.call(
                 "username <old_email@example.com>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
-                    )
-                ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
+                    ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": stub_user.id,
@@ -1176,16 +1169,14 @@ def test_collaborator_added_email(
         assert send_email.delay.calls == [
             pretend.call(
                 "username <email@example.com>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
-                    )
-                ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
+                    ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": stub_user.id,
@@ -1200,16 +1191,14 @@ def test_collaborator_added_email(
             ),
             pretend.call(
                 "submitterusername <submiteremail@example.com>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
-                    )
-                ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
+                    ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": stub_submitter_user.id,
@@ -1302,16 +1291,14 @@ def test_collaborator_added_email_unverified(
         assert send_email.delay.calls == [
             pretend.call(
                 "submitterusername <submiteremail@example.com>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
-                    )
-                ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
+                    ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": stub_submitter_user.id,
@@ -1387,16 +1374,14 @@ def test_project_role_verification_email(
         assert send_email.delay.calls == [
             pretend.call(
                 f"{stub_user.name} <{stub_user.email}>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
-                    )
-                ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
+                    ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": stub_user.id,
@@ -1481,16 +1466,14 @@ def test_added_as_collaborator_email(
         assert send_email.delay.calls == [
             pretend.call(
                 "username <email@example.com>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
-                    )
-                ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
+                    ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": stub_user.id,
@@ -1630,16 +1613,14 @@ def test_collaborator_removed_email(self, db_request, pyramid_config, monkeypatc
         assert send_email.delay.calls == [
             pretend.call(
                 f"{ removed_user.name } <{ removed_user.primary_email.email }>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
-                    )
-                ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
+                    ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": removed_user.id,
@@ -1654,16 +1635,14 @@ def test_collaborator_removed_email(self, db_request, pyramid_config, monkeypatc
             ),
             pretend.call(
                 f"{ submitter_user.name } <{ submitter_user.primary_email.email }>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
-                    )
-                ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
+                    ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": submitter_user.id,
@@ -1731,16 +1710,14 @@ def test_removed_as_collaborator_email(
         assert send_email.delay.calls == [
             pretend.call(
                 f"{ removed_user.name } <{ removed_user.primary_email.email }>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
-                    )
-                ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
+                    ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": removed_user.id,
@@ -1817,16 +1794,14 @@ def test_role_changed_email(self, db_request, pyramid_config, monkeypatch):
         assert send_email.delay.calls == [
             pretend.call(
                 f"{ changed_user.name } <{ changed_user.primary_email.email }>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
-                    )
-                ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
+                    ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": changed_user.id,
@@ -1841,16 +1816,14 @@ def test_role_changed_email(self, db_request, pyramid_config, monkeypatch):
             ),
             pretend.call(
                 f"{ submitter_user.name } <{ submitter_user.primary_email.email }>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
-                    )
-                ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
+                    ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": submitter_user.id,
@@ -1922,16 +1895,14 @@ def test_role_changed_as_collaborator_email(
         assert send_email.delay.calls == [
             pretend.call(
                 f"{ changed_user.name } <{ changed_user.primary_email.email }>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
-                    )
-                ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
+                    ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": changed_user.id,
@@ -2027,16 +1998,14 @@ def test_removed_project_email_to_maintainer(
         assert send_email.delay.calls == [
             pretend.call(
                 "username <email@example.com>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
                     ),
-                ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": stub_user.id,
@@ -2051,16 +2020,14 @@ def test_removed_project_email_to_maintainer(
             ),
             pretend.call(
                 "submitterusername <submiteremail@example.com>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
-                    )
-                ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
+                    ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": stub_submitter_user.id,
@@ -2154,16 +2121,14 @@ def test_removed_project_email_to_owner(
         assert send_email.delay.calls == [
             pretend.call(
                 "username <email@example.com>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
                     ),
-                ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": stub_user.id,
@@ -2178,16 +2143,14 @@ def test_removed_project_email_to_owner(
             ),
             pretend.call(
                 "submitterusername <submiteremail@example.com>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
-                    )
-                ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
+                    ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": stub_submitter_user.id,
@@ -2297,16 +2260,14 @@ def test_send_yanked_project_release_email_to_maintainer(
         assert send_email.delay.calls == [
             pretend.call(
                 "username <email@example.com>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
                     ),
-                ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": stub_user.id,
@@ -2321,16 +2282,14 @@ def test_send_yanked_project_release_email_to_maintainer(
             ),
             pretend.call(
                 "submitterusername <submiteremail@example.com>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
-                    )
-                ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
+                    ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": stub_submitter_user.id,
@@ -2438,16 +2397,14 @@ def test_send_yanked_project_release_email_to_owner(
         assert send_email.delay.calls == [
             pretend.call(
                 "username <email@example.com>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
                     ),
-                ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": stub_user.id,
@@ -2462,16 +2419,14 @@ def test_send_yanked_project_release_email_to_owner(
             ),
             pretend.call(
                 "submitterusername <submiteremail@example.com>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
-                    )
-                ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
+                    ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": stub_submitter_user.id,
@@ -2580,16 +2535,14 @@ def test_send_unyanked_project_release_email_to_maintainer(
         assert send_email.delay.calls == [
             pretend.call(
                 "username <email@example.com>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
                     ),
-                ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": stub_user.id,
@@ -2604,16 +2557,14 @@ def test_send_unyanked_project_release_email_to_maintainer(
             ),
             pretend.call(
                 "submitterusername <submiteremail@example.com>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
-                    )
-                ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
+                    ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": stub_submitter_user.id,
@@ -2720,16 +2671,14 @@ def test_send_unyanked_project_release_email_to_owner(
         assert send_email.delay.calls == [
             pretend.call(
                 "username <email@example.com>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
                     ),
-                ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": stub_user.id,
@@ -2744,16 +2693,14 @@ def test_send_unyanked_project_release_email_to_owner(
             ),
             pretend.call(
                 "submitterusername <submiteremail@example.com>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
-                    )
-                ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
+                    ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": stub_submitter_user.id,
@@ -2862,16 +2809,14 @@ def test_send_removed_project_release_email_to_maintainer(
         assert send_email.delay.calls == [
             pretend.call(
                 "username <email@example.com>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
                     ),
-                ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": stub_user.id,
@@ -2886,16 +2831,14 @@ def test_send_removed_project_release_email_to_maintainer(
             ),
             pretend.call(
                 "submitterusername <submiteremail@example.com>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
-                    )
-                ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
+                    ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": stub_submitter_user.id,
@@ -3002,16 +2945,14 @@ def test_send_removed_project_release_email_to_owner(
         assert send_email.delay.calls == [
             pretend.call(
                 "username <email@example.com>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
                     ),
-                ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": stub_user.id,
@@ -3026,16 +2967,14 @@ def test_send_removed_project_release_email_to_owner(
             ),
             pretend.call(
                 "submitterusername <submiteremail@example.com>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
-                    )
-                ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
+                    ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": stub_submitter_user.id,
@@ -3145,16 +3084,14 @@ def test_send_removed_project_release_file_email_to_owner(
         assert send_email.delay.calls == [
             pretend.call(
                 "username <email@example.com>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
                     ),
-                ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": stub_user.id,
@@ -3169,16 +3106,14 @@ def test_send_removed_project_release_file_email_to_owner(
             ),
             pretend.call(
                 "submitterusername <submiteremail@example.com>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
-                    )
-                ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
+                    ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": stub_submitter_user.id,
@@ -3286,16 +3221,14 @@ def test_send_removed_project_release_file_email_to_maintainer(
         assert send_email.delay.calls == [
             pretend.call(
                 "username <email@example.com>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
                     ),
-                ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": stub_user.id,
@@ -3310,16 +3243,14 @@ def test_send_removed_project_release_file_email_to_maintainer(
             ),
             pretend.call(
                 "submitterusername <submiteremail@example.com>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
-                    )
-                ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
+                    ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": stub_submitter_user.id,
@@ -3401,16 +3332,14 @@ def test_two_factor_email(
         assert send_email.delay.calls == [
             pretend.call(
                 f"{stub_user.username} <{stub_user.email}>",
-                attr.asdict(
-                    EmailMessage(
-                        subject="Email Subject",
-                        body_text="Email Body",
-                        body_html=(
-                            "<html>\n<head></head>\n"
-                            "<body><p>Email HTML Body</p></body>\n</html>\n"
-                        ),
-                    )
-                ),
+                {
+                    "subject": "Email Subject",
+                    "body_text": "Email Body",
+                    "body_html": (
+                        "<html>\n<head></head>\n"
+                        "<body><p>Email HTML Body</p></body>\n</html>\n"
+                    ),
+                },
                 {
                     "tag": "account:email:sent",
                     "user_id": stub_user.id,