1818from openedx .core .djangoapps .site_configuration import helpers as configuration_helpers
1919from openedx .core .djangoapps .user_authn .utils import check_pwned_password
2020from openedx .core .lib .celery .task_utils import emulate_http_request
21- from openedx . core . djangoapps . ace_common . utils import ENABLE_SES_FOR_ACCOUNT_ACTIVATION
21+ from edx_toggles . toggles import WaffleFlag
2222
2323log = logging .getLogger ('edx.celery.task' )
2424
25+ # .. toggle_name: user_authn.enable_ses_for_account_activation
26+ # .. toggle_implementation: WaffleFlag
27+ # .. toggle_default: False
28+ # .. toggle_description: Route account activation emails via SES using ACE.
29+ # .. toggle_use_cases: opt_in, temporary
30+ # .. toggle_creation_date: 2026-03-31
31+ # .. toggle_target_removal_date: None
32+ # .. toggle_warning: Controls SES routing for account activation emails.
33+
34+ ENABLE_SES_FOR_ACCOUNT_ACTIVATION = WaffleFlag (
35+ 'user_authn.enable_ses_for_account_activation' ,
36+ __name__ ,
37+ )
38+
2539
2640@shared_task
2741@set_code_owner_attribute
@@ -79,59 +93,28 @@ def send_activation_email(self, msg_string, from_address=None, site_id=None):
7993 sent_via_ses = False
8094
8195 if route_via_ses :
82- msg .options .update ({
83- 'override_default_channel' : 'django_email' ,
84- 'transactional' : True ,
85- 'from_address' : configuration_helpers .get_value (
86- 'ACTIVATION_EMAIL_FROM_ADDRESS'
87- ) or configuration_helpers .get_value (
88- 'email_from_address' ,
89- settings .DEFAULT_FROM_EMAIL
90- ),
91- })
96+ msg .options ['override_default_channel' ] = 'django_email'
9297
9398 try :
9499 with emulate_http_request (site = site , user = user ):
95100 ace .send (msg )
96101 sent_via_ses = route_via_ses
97102
98103 except RecoverableChannelDeliveryError :
99- log .warning (
100- "SES send failed for %s, falling back to default ACE channel" ,
101- dest_addr ,
102- exc_info = True ,
103- )
104-
105- if not route_via_ses :
106- log .info (
107- 'Retrying sending email to user {dest_addr}, attempt # {attempt} of {max_attempts}' .format (
108- dest_addr = dest_addr ,
109- attempt = retries ,
110- max_attempts = max_retries
111- )
104+ if route_via_ses :
105+ log .warning (
106+ "SES send failed for %s, falling back to default ACE channel" ,
107+ dest_addr ,
108+ exc_info = True ,
112109 )
113- try :
114- self .retry (
115- countdown = settings .RETRY_ACTIVATION_EMAIL_TIMEOUT ,
116- max_retries = max_retries
117- )
118- except MaxRetriesExceededError :
119- log .error (
120- 'Unable to send activation email to user from "%s" to "%s"' ,
121- from_address ,
122- dest_addr ,
123- exc_info = True
124- )
125- return
126110
127- _remove_ses_overrides ( msg )
111+ msg . options . pop ( 'override_default_channel' , None )
128112
129- try :
130113 with emulate_http_request (site = site , user = user ):
131114 ace .send (msg )
132115 sent_via_ses = False
133116
134- except RecoverableChannelDeliveryError :
117+ else :
135118 log .info (
136119 'Retrying sending email to user {dest_addr}, attempt # {attempt} of {max_attempts}' .format (
137120 dest_addr = dest_addr ,
@@ -151,6 +134,8 @@ def send_activation_email(self, msg_string, from_address=None, site_id=None):
151134 dest_addr ,
152135 exc_info = True
153136 )
137+ return
138+
154139 except Exception :
155140 log .exception (
156141 'Unable to send activation email to user from "%s" to "%s"' ,
@@ -164,9 +149,3 @@ def send_activation_email(self, msg_string, from_address=None, site_id=None):
164149 dest_addr ,
165150 'SES' if sent_via_ses else 'default ACE channel' ,
166151 )
167-
168-
169- def _remove_ses_overrides (msg ):
170- msg .options .pop ('override_default_channel' , None )
171- msg .options .pop ('transactional' , None )
172- msg .options .pop ('from_address' , None )
0 commit comments