We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Modify domain invitation script to process "friends of the show" first, then incrementally process others
### Issue description

We have a few domain managers that we'll invite to the registrar first. Let's modify the domain invitation script to send to a defined set of domains first. 

We also shouldn't blast thousands of emails out to the internet, but incrementally roll them out.

### Acceptance criteria

- [ ] Invitation script works with a product owner-specified list of domains/contacts (before sending to everyone else)
- [ ] Script slow rolls out invitations. Could be percentage-based (1/2/5/10/20/45/75/100) or volume-based (a few hundred at a time)

### Additional context

_No response_

### Links to other issues

🔄 Related to PR #1038

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/registrar/management/commands/send_domain_invitations.py`
Content:
```
1 """Data migration: Send domain invitations once to existing customers."""
2 
3 import logging
4 import copy
5 
6 from django.core.management import BaseCommand
7 from registrar.models import TransitionDomain
8 from ...utility.email import send_templated_email, EmailSendingError
9 from typing import List
10 
11 logger = logging.getLogger(__name__)
12 
13 
14 class Command(BaseCommand):
15     help = "Send domain invitations once to existing customers."
16 
17     # this array is used to store and process the transition_domains
18     transition_domains: List[str] = []
19     # this array is used to store domains with errors, which are not
20     # sent emails; this array is used to update the succesful
21     # transition_domains to email_sent=True, and also to report
22     # out errors
23     domains_with_errors: List[str] = []
24     # this array is used to store email_context; each item in the array
25     # contains the context for a single email; single emails may be 1
26     # or more transition_domains, as they are grouped by username
27     emails_to_send: List[str] = []
28 
29     def add_arguments(self, parser):
30         """Add command line arguments."""
31         parser.add_argument(
32             "-s",
33             "--send_emails",
34             action="store_true",
35             default=False,
36             dest="send_emails",
37             help="Send emails ",
38         )
39 
40     def handle(self, **options):
41         """Process the objects in TransitionDomain."""
42 
43         logger.info("checking domains and preparing emails")
44         # Get all TransitionDomain objects
45         self.transition_domains = TransitionDomain.objects.filter(
46             email_sent=False,
47         ).order_by("username")
48         logger.info("Found %d transition domains", len(self.transition_domains))
49 
50         self.build_emails_to_send_array()
51         logger.info("Prepared %d emails to send", len(self.emails_to_send))
52 
53         if options["send_emails"]:
54             logger.info("about to send emails")
55             self.send_emails()
56             logger.info("done sending emails")
57 
58             self.update_domains_as_sent()
59 
60             logger.info("done sending emails and updating transition_domains")
61         else:
62             logger.info("not sending emails")
63             for email_context in self.emails_to_send:
64                 logger.info(
65                     "would send email to %s for %s",
66                     email_context["email"],
67                     email_context["domains"],
68                 )
69 
70     def build_emails_to_send_array(self):
71         """this method sends emails to distinct usernames"""
72 
73         # data structure to hold email context for a single email;
74         # transition_domains ordered by username, a single email_context
75         # may include information from more than one transition_domain
76         email_context = {"email": ""}
77 
78         # loop through all transition_domains; group them by username
79         # into emails_to_send_array
80         for transition_domain in self.transition_domains:
81             # attempt to get the domain from domain objects; if there is
82             # an error getting the domain, skip this domain and add it to
83             # domains_with_errors
84             try:
85                 # if prior username does not match current username
86                 if not email_context["email"] or email_context["email"] != transition_domain.username:
87                     # if not first in list of transition_domains
88                     if email_context["email"]:
89                         # append the email context to the emails_to_send array
90                         self.emails_to_send.append(copy.deepcopy(email_context))
91                     email_context["domains"] = []
92                 email_context["email"] = transition_domain.username
93                 email_context["domains"].append(transition_domain.domain_name)
94             except Exception as err:
95                 # error condition if domain not in database
96                 self.domains_with_errors.append(copy.deepcopy(transition_domain.domain_name))
97                 logger.error(f"error retrieving domain {transition_domain.domain_name}: {err}")
98         # if there are at least one more transition domains than errors,
99         # then append one more item
100         if len(self.transition_domains) > len(self.domains_with_errors):
101             self.emails_to_send.append(email_context)
102 
103     def send_emails(self):
104         if len(self.emails_to_send) > 0:
105             for email_data in self.emails_to_send:
106                 self.send_email(email_data)
107         else:
108             logger.info("no emails to send")
109 
110     def send_email(self, email_data):
111         try:
112             send_templated_email(
113                 "emails/transition_domain_invitation.txt",
114                 "emails/transition_domain_invitation_subject.txt",
115                 to_address=email_data["email"],
116                 context={
117                     "domains": email_data["domains"],
118                 },
119             )
120             # success message is logged
121             logger.info(
122                 f"email sent successfully to {email_data['email']} for "
123                 f"{[domain for domain in email_data['domains']]}"
124             )
125         except EmailSendingError as err:
126             logger.error(
127                 f"email did not send successfully to {email_data['email']} "
128                 f"for {[domain for domain in email_data['domains']]}"
129                 f": {err}"
130             )
131             # if email failed to send, set error in domains_with_errors for each
132             # domain in the email so that transition domain email_sent is not set
133             # to True
134             for domain in email_data["domains"]:
135                 self.domains_with_errors.append(domain)
136 
137     def update_domains_as_sent(self):
138         """set email_sent to True in all transition_domains which have
139         been processed successfully"""
140         for transition_domain in self.transition_domains:
141             if transition_domain.domain_name not in self.domains_with_errors:
142                 transition_domain.email_sent = True
143                 transition_domain.save()
144
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/src/registrar/management/commands/send_domain_invitations.py b/src/registrar/management/commands/send_domain_invitations.py
--- a/src/registrar/management/commands/send_domain_invitations.py
+++ b/src/registrar/management/commands/send_domain_invitations.py
@@ -37,14 +37,24 @@
             help="Send emails ",
         )
 
+        parser.add_argument("emails", nargs="*", help="Email addresses to send invitations to")
+
     def handle(self, **options):
         """Process the objects in TransitionDomain."""
 
         logger.info("checking domains and preparing emails")
-        # Get all TransitionDomain objects
-        self.transition_domains = TransitionDomain.objects.filter(
-            email_sent=False,
-        ).order_by("username")
+
+        if options["emails"]:
+            # this option is a list of email addresses
+            self.transition_domains = TransitionDomain.objects.filter(
+                username__in=options["emails"],
+                email_sent=False,
+            ).order_by("username")
+        else:
+            # Get all TransitionDomain objects
+            self.transition_domains = TransitionDomain.objects.filter(
+                email_sent=False,
+            ).order_by("username")
         logger.info("Found %d transition domains", len(self.transition_domains))
 
         self.build_emails_to_send_array()

{"golden_diff": "diff --git a/src/registrar/management/commands/send_domain_invitations.py b/src/registrar/management/commands/send_domain_invitations.py\n--- a/src/registrar/management/commands/send_domain_invitations.py\n+++ b/src/registrar/management/commands/send_domain_invitations.py\n@@ -37,14 +37,24 @@\n             help=\"Send emails \",\n         )\n \n+        parser.add_argument(\"emails\", nargs=\"*\", help=\"Email addresses to send invitations to\")\n+\n     def handle(self, **options):\n         \"\"\"Process the objects in TransitionDomain.\"\"\"\n \n         logger.info(\"checking domains and preparing emails\")\n-        # Get all TransitionDomain objects\n-        self.transition_domains = TransitionDomain.objects.filter(\n-            email_sent=False,\n-        ).order_by(\"username\")\n+\n+        if options[\"emails\"]:\n+            # this option is a list of email addresses\n+            self.transition_domains = TransitionDomain.objects.filter(\n+                username__in=options[\"emails\"],\n+                email_sent=False,\n+            ).order_by(\"username\")\n+        else:\n+            # Get all TransitionDomain objects\n+            self.transition_domains = TransitionDomain.objects.filter(\n+                email_sent=False,\n+            ).order_by(\"username\")\n         logger.info(\"Found %d transition domains\", len(self.transition_domains))\n \n         self.build_emails_to_send_array()\n", "issue": "Modify domain invitation script to process \"friends of the show\" first, then incrementally process others\n### Issue description\n\nWe have a few domain managers that we'll invite to the registrar first. Let's modify the domain invitation script to send to a defined set of domains first. \r\n\r\nWe also shouldn't blast thousands of emails out to the internet, but incrementally roll them out.\n\n### Acceptance criteria\n\n- [ ] Invitation script works with a product owner-specified list of domains/contacts (before sending to everyone else)\r\n- [ ] Script slow rolls out invitations. Could be percentage-based (1/2/5/10/20/45/75/100) or volume-based (a few hundred at a time)\n\n### Additional context\n\n_No response_\n\n### Links to other issues\n\n\ud83d\udd04 Related to PR #1038\n", "before_files": [{"content": "\"\"\"Data migration: Send domain invitations once to existing customers.\"\"\"\n\nimport logging\nimport copy\n\nfrom django.core.management import BaseCommand\nfrom registrar.models import TransitionDomain\nfrom ...utility.email import send_templated_email, EmailSendingError\nfrom typing import List\n\nlogger = logging.getLogger(__name__)\n\n\nclass Command(BaseCommand):\n    help = \"Send domain invitations once to existing customers.\"\n\n    # this array is used to store and process the transition_domains\n    transition_domains: List[str] = []\n    # this array is used to store domains with errors, which are not\n    # sent emails; this array is used to update the succesful\n    # transition_domains to email_sent=True, and also to report\n    # out errors\n    domains_with_errors: List[str] = []\n    # this array is used to store email_context; each item in the array\n    # contains the context for a single email; single emails may be 1\n    # or more transition_domains, as they are grouped by username\n    emails_to_send: List[str] = []\n\n    def add_arguments(self, parser):\n        \"\"\"Add command line arguments.\"\"\"\n        parser.add_argument(\n            \"-s\",\n            \"--send_emails\",\n            action=\"store_true\",\n            default=False,\n            dest=\"send_emails\",\n            help=\"Send emails \",\n        )\n\n    def handle(self, **options):\n        \"\"\"Process the objects in TransitionDomain.\"\"\"\n\n        logger.info(\"checking domains and preparing emails\")\n        # Get all TransitionDomain objects\n        self.transition_domains = TransitionDomain.objects.filter(\n            email_sent=False,\n        ).order_by(\"username\")\n        logger.info(\"Found %d transition domains\", len(self.transition_domains))\n\n        self.build_emails_to_send_array()\n        logger.info(\"Prepared %d emails to send\", len(self.emails_to_send))\n\n        if options[\"send_emails\"]:\n            logger.info(\"about to send emails\")\n            self.send_emails()\n            logger.info(\"done sending emails\")\n\n            self.update_domains_as_sent()\n\n            logger.info(\"done sending emails and updating transition_domains\")\n        else:\n            logger.info(\"not sending emails\")\n            for email_context in self.emails_to_send:\n                logger.info(\n                    \"would send email to %s for %s\",\n                    email_context[\"email\"],\n                    email_context[\"domains\"],\n                )\n\n    def build_emails_to_send_array(self):\n        \"\"\"this method sends emails to distinct usernames\"\"\"\n\n        # data structure to hold email context for a single email;\n        # transition_domains ordered by username, a single email_context\n        # may include information from more than one transition_domain\n        email_context = {\"email\": \"\"}\n\n        # loop through all transition_domains; group them by username\n        # into emails_to_send_array\n        for transition_domain in self.transition_domains:\n            # attempt to get the domain from domain objects; if there is\n            # an error getting the domain, skip this domain and add it to\n            # domains_with_errors\n            try:\n                # if prior username does not match current username\n                if not email_context[\"email\"] or email_context[\"email\"] != transition_domain.username:\n                    # if not first in list of transition_domains\n                    if email_context[\"email\"]:\n                        # append the email context to the emails_to_send array\n                        self.emails_to_send.append(copy.deepcopy(email_context))\n                    email_context[\"domains\"] = []\n                email_context[\"email\"] = transition_domain.username\n                email_context[\"domains\"].append(transition_domain.domain_name)\n            except Exception as err:\n                # error condition if domain not in database\n                self.domains_with_errors.append(copy.deepcopy(transition_domain.domain_name))\n                logger.error(f\"error retrieving domain {transition_domain.domain_name}: {err}\")\n        # if there are at least one more transition domains than errors,\n        # then append one more item\n        if len(self.transition_domains) > len(self.domains_with_errors):\n            self.emails_to_send.append(email_context)\n\n    def send_emails(self):\n        if len(self.emails_to_send) > 0:\n            for email_data in self.emails_to_send:\n                self.send_email(email_data)\n        else:\n            logger.info(\"no emails to send\")\n\n    def send_email(self, email_data):\n        try:\n            send_templated_email(\n                \"emails/transition_domain_invitation.txt\",\n                \"emails/transition_domain_invitation_subject.txt\",\n                to_address=email_data[\"email\"],\n                context={\n                    \"domains\": email_data[\"domains\"],\n                },\n            )\n            # success message is logged\n            logger.info(\n                f\"email sent successfully to {email_data['email']} for \"\n                f\"{[domain for domain in email_data['domains']]}\"\n            )\n        except EmailSendingError as err:\n            logger.error(\n                f\"email did not send successfully to {email_data['email']} \"\n                f\"for {[domain for domain in email_data['domains']]}\"\n                f\": {err}\"\n            )\n            # if email failed to send, set error in domains_with_errors for each\n            # domain in the email so that transition domain email_sent is not set\n            # to True\n            for domain in email_data[\"domains\"]:\n                self.domains_with_errors.append(domain)\n\n    def update_domains_as_sent(self):\n        \"\"\"set email_sent to True in all transition_domains which have\n        been processed successfully\"\"\"\n        for transition_domain in self.transition_domains:\n            if transition_domain.domain_name not in self.domains_with_errors:\n                transition_domain.email_sent = True\n                transition_domain.save()\n", "path": "src/registrar/management/commands/send_domain_invitations.py"}], "after_files": [{"content": "\"\"\"Data migration: Send domain invitations once to existing customers.\"\"\"\n\nimport logging\nimport copy\n\nfrom django.core.management import BaseCommand\nfrom registrar.models import TransitionDomain\nfrom ...utility.email import send_templated_email, EmailSendingError\nfrom typing import List\n\nlogger = logging.getLogger(__name__)\n\n\nclass Command(BaseCommand):\n    help = \"Send domain invitations once to existing customers.\"\n\n    # this array is used to store and process the transition_domains\n    transition_domains: List[str] = []\n    # this array is used to store domains with errors, which are not\n    # sent emails; this array is used to update the succesful\n    # transition_domains to email_sent=True, and also to report\n    # out errors\n    domains_with_errors: List[str] = []\n    # this array is used to store email_context; each item in the array\n    # contains the context for a single email; single emails may be 1\n    # or more transition_domains, as they are grouped by username\n    emails_to_send: List[str] = []\n\n    def add_arguments(self, parser):\n        \"\"\"Add command line arguments.\"\"\"\n        parser.add_argument(\n            \"-s\",\n            \"--send_emails\",\n            action=\"store_true\",\n            default=False,\n            dest=\"send_emails\",\n            help=\"Send emails \",\n        )\n\n        parser.add_argument(\"emails\", nargs=\"*\", help=\"Email addresses to send invitations to\")\n\n    def handle(self, **options):\n        \"\"\"Process the objects in TransitionDomain.\"\"\"\n\n        logger.info(\"checking domains and preparing emails\")\n\n        if options[\"emails\"]:\n            # this option is a list of email addresses\n            self.transition_domains = TransitionDomain.objects.filter(\n                username__in=options[\"emails\"],\n                email_sent=False,\n            ).order_by(\"username\")\n        else:\n            # Get all TransitionDomain objects\n            self.transition_domains = TransitionDomain.objects.filter(\n                email_sent=False,\n            ).order_by(\"username\")\n        logger.info(\"Found %d transition domains\", len(self.transition_domains))\n\n        self.build_emails_to_send_array()\n        logger.info(\"Prepared %d emails to send\", len(self.emails_to_send))\n\n        if options[\"send_emails\"]:\n            logger.info(\"about to send emails\")\n            self.send_emails()\n            logger.info(\"done sending emails\")\n\n            self.update_domains_as_sent()\n\n            logger.info(\"done sending emails and updating transition_domains\")\n        else:\n            logger.info(\"not sending emails\")\n            for email_context in self.emails_to_send:\n                logger.info(\n                    \"would send email to %s for %s\",\n                    email_context[\"email\"],\n                    email_context[\"domains\"],\n                )\n\n    def build_emails_to_send_array(self):\n        \"\"\"this method sends emails to distinct usernames\"\"\"\n\n        # data structure to hold email context for a single email;\n        # transition_domains ordered by username, a single email_context\n        # may include information from more than one transition_domain\n        email_context = {\"email\": \"\"}\n\n        # loop through all transition_domains; group them by username\n        # into emails_to_send_array\n        for transition_domain in self.transition_domains:\n            # attempt to get the domain from domain objects; if there is\n            # an error getting the domain, skip this domain and add it to\n            # domains_with_errors\n            try:\n                # if prior username does not match current username\n                if not email_context[\"email\"] or email_context[\"email\"] != transition_domain.username:\n                    # if not first in list of transition_domains\n                    if email_context[\"email\"]:\n                        # append the email context to the emails_to_send array\n                        self.emails_to_send.append(copy.deepcopy(email_context))\n                    email_context[\"domains\"] = []\n                email_context[\"email\"] = transition_domain.username\n                email_context[\"domains\"].append(transition_domain.domain_name)\n            except Exception as err:\n                # error condition if domain not in database\n                self.domains_with_errors.append(copy.deepcopy(transition_domain.domain_name))\n                logger.error(f\"error retrieving domain {transition_domain.domain_name}: {err}\")\n        # if there are at least one more transition domains than errors,\n        # then append one more item\n        if len(self.transition_domains) > len(self.domains_with_errors):\n            self.emails_to_send.append(email_context)\n\n    def send_emails(self):\n        if len(self.emails_to_send) > 0:\n            for email_data in self.emails_to_send:\n                self.send_email(email_data)\n        else:\n            logger.info(\"no emails to send\")\n\n    def send_email(self, email_data):\n        try:\n            send_templated_email(\n                \"emails/transition_domain_invitation.txt\",\n                \"emails/transition_domain_invitation_subject.txt\",\n                to_address=email_data[\"email\"],\n                context={\n                    \"domains\": email_data[\"domains\"],\n                },\n            )\n            # success message is logged\n            logger.info(\n                f\"email sent successfully to {email_data['email']} for \"\n                f\"{[domain for domain in email_data['domains']]}\"\n            )\n        except EmailSendingError as err:\n            logger.error(\n                f\"email did not send successfully to {email_data['email']} \"\n                f\"for {[domain for domain in email_data['domains']]}\"\n                f\": {err}\"\n            )\n            # if email failed to send, set error in domains_with_errors for each\n            # domain in the email so that transition domain email_sent is not set\n            # to True\n            for domain in email_data[\"domains\"]:\n                self.domains_with_errors.append(domain)\n\n    def update_domains_as_sent(self):\n        \"\"\"set email_sent to True in all transition_domains which have\n        been processed successfully\"\"\"\n        for transition_domain in self.transition_domains:\n            if transition_domain.domain_name not in self.domains_with_errors:\n                transition_domain.email_sent = True\n                transition_domain.save()\n", "path": "src/registrar/management/commands/send_domain_invitations.py"}]}