Skip to content

Commit 2ef4f0b

Browse files
authored
Merge pull request #770 from GSA/feature/678-add-guid-to-gspc-emails
Feature/678 add guid to gspc emails
2 parents b7976c6 + d9a83a7 commit 2ef4f0b

2 files changed

Lines changed: 23 additions & 15 deletions

File tree

training-front-end/src/components/AdminGSPC.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@
173173
class="usa-alert--slim"
174174
:has-heading="false"
175175
>
176-
Emails successfully sent to {{ successCount }} people.
176+
Emails sending to {{ successCount }} people.
177177
</USWDSAlert>
178178
</div>
179179
<div class="grid-row grid-gap margin-top-3">

training/api/email.py

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,20 @@ class InviteTuple(NamedTuple):
118118

119119

120120
def send_gspc_invite_emails(invites: list[InviteTuple], app_settings: Settings) -> None:
121+
"""Background task designed to do a bulk send of GSPC invite emails"""
122+
# Start timer to track how long the job takes
123+
start_time = time.time()
121124
logging.info(f"Starting gspc invite job, number of invites:{len(invites)}")
125+
122126
email_messages = [create_email_message(invite, app_settings) for invite in invites]
123-
send_emails_in_batches(email_messages=email_messages, batch_size=10, app_settings=app_settings)
124-
logging.info("Finished gspc invite job")
127+
send_emails_in_batches(email_messages=email_messages, batch_size=25, app_settings=app_settings)
128+
129+
end_time = time.time()
130+
execution_time = end_time - start_time
131+
# Format time as minutes and seconds for better readability
132+
minutes = int(execution_time // 60)
133+
seconds = int(execution_time % 60)
134+
logging.info(f"Finished gspc invite job. Total execution time: {minutes} minutes and {seconds} seconds for {len(invites)} emails")
125135

126136

127137
def create_email_message(invite: InviteTuple, app_settings: Settings) -> EmailMessage:
@@ -149,31 +159,29 @@ def batch_iterator(items: List, batch_size: int) -> Iterator:
149159

150160

151161
def send_emails_in_batches(email_messages: List[EmailMessage], batch_size: int, app_settings: Settings) -> None:
162+
"""Chunks the list into batches and attempts to send each back of emails."""
152163
for batch in batch_iterator(email_messages, batch_size):
153164
max_retries = 3
165+
# Attempt to trigger email batch, retries on failure
154166
for attempt in range(max_retries):
155167
try:
156168
with SMTP(app_settings.SMTP_SERVER, port=app_settings.SMTP_PORT, timeout=30) as smtp:
157169
smtp.starttls()
158170
if app_settings.SMTP_USER and app_settings.SMTP_PASSWORD:
159171
smtp.login(user=app_settings.SMTP_USER, password=app_settings.SMTP_PASSWORD)
160172

161-
logging.info(f"Sending emails with account: {str(app_settings.SMTP_PASSWORD)}")
162-
163173
# Send messages in current batch
164174
for message in batch:
165-
try:
166-
smtp.send_message(message)
167-
except Exception as e:
168-
# Log the error but continue with remaining messages
169-
logging.error(f"Failed to send email to {message['To']}: {str(e)}")
175+
smtp.send_message(message)
170176
smtp.quit()
171-
177+
break # Exit retry loop if successful
172178
except Exception as e:
173179
if attempt < max_retries - 1:
174-
# Wait with exponential backoff: 2, 4, 8 seconds...
175-
sleep_time = 2 ** attempt
180+
# Wait with backoff: 1, 2, 4 seconds...
181+
sleep_time = 1 * (attempt + 1)
176182
time.sleep(sleep_time)
183+
# Log the error after all retries failed
177184
else:
178-
# Log the error after all retries failed
179-
logging.error(f"Failed to send batch after {max_retries} attempts: {str(e)}")
185+
# Extract all email addresses from the batch and join them with commas
186+
addresses_list = ", ".join([message['To'] for message in batch])
187+
logging.error(f"Failed to send batch after {max_retries} attempts: {str(e)}. Addresses: {addresses_list}")

0 commit comments

Comments
 (0)