@@ -59,6 +59,14 @@ def _send_scenario_for_program(scenario, program, scheduled_for):
5959 if not user_ids :
6060 return 0
6161
62+ logger .info (
63+ "Scenario %s program=%s scheduled_for=%s recipients=%s" ,
64+ scenario .code ,
65+ program .id ,
66+ scheduled_for ,
67+ len (user_ids ),
68+ )
69+
6270 MailingScenarioLog .objects .filter (
6371 scenario_code = scenario .code ,
6472 program = program ,
@@ -84,26 +92,88 @@ def _send_scenario_for_program(scenario, program, scheduled_for):
8492 def context_builder (user ):
8593 return scenario .context_builder (program , user , deadline_date )
8694
95+ sent_count = 0
96+ failed_count = 0
97+
98+ def _normalize_status (status_value ):
99+ if status_value is None :
100+ return set ()
101+ if isinstance (status_value , dict ):
102+ return {str (key ) for key in status_value .keys ()}
103+ if isinstance (status_value , (set , list , tuple )):
104+ return {str (item ) for item in status_value }
105+ return {str (status_value )}
106+
87107 def status_callback (user , msg ):
108+ nonlocal sent_count , failed_count
88109 status = getattr (msg , "anymail_status" , None )
89110 message_id = getattr (status , "message_id" , None ) if status else None
90- if message_id :
91- logger .info (
92- "Scenario %s user=%s anymail_id=%s status=%s" ,
111+ status_set = _normalize_status (getattr (status , "status" , None ))
112+ status_str = "," .join (sorted (status_set )) if status_set else "unknown"
113+ is_failed = bool (status_set & {"rejected" , "failed" , "invalid" , "bounced" })
114+
115+ if not message_id :
116+ failed_count += 1
117+ MailingScenarioLog .objects .filter (
118+ scenario_code = scenario .code ,
119+ program = program ,
120+ scheduled_for = scheduled_for ,
121+ status = MailingScenarioLog .Status .PENDING ,
122+ user_id = user .id ,
123+ ).update (
124+ status = MailingScenarioLog .Status .FAILED ,
125+ error = "anymail_status missing" ,
126+ )
127+ logger .warning (
128+ "Scenario %s user=%s anymail_status missing" ,
93129 scenario .code ,
94130 user .id ,
95- message_id ,
96- getattr (status , "status" , None ),
97131 )
98- else :
99- logger .info (
100- "Scenario %s user=%s anymail_status missing" ,
132+ return
133+
134+ if is_failed :
135+ failed_count += 1
136+ MailingScenarioLog .objects .filter (
137+ scenario_code = scenario .code ,
138+ program = program ,
139+ scheduled_for = scheduled_for ,
140+ status = MailingScenarioLog .Status .PENDING ,
141+ user_id = user .id ,
142+ ).update (
143+ status = MailingScenarioLog .Status .FAILED ,
144+ error = f"anymail_status={ status_str } anymail_id={ message_id } " ,
145+ )
146+ logger .error (
147+ "Scenario %s user=%s anymail_id=%s status=%s" ,
101148 scenario .code ,
102149 user .id ,
150+ message_id ,
151+ status_str ,
103152 )
153+ return
154+
155+ sent_count += 1
156+ MailingScenarioLog .objects .filter (
157+ scenario_code = scenario .code ,
158+ program = program ,
159+ scheduled_for = scheduled_for ,
160+ status = MailingScenarioLog .Status .PENDING ,
161+ user_id = user .id ,
162+ ).update (
163+ status = MailingScenarioLog .Status .SENT ,
164+ sent_at = timezone .now (),
165+ error = "" ,
166+ )
167+ logger .info (
168+ "Scenario %s user=%s anymail_id=%s status=%s" ,
169+ scenario .code ,
170+ user .id ,
171+ message_id ,
172+ status_str ,
173+ )
104174
105175 try :
106- send_mass_mail_from_template (
176+ num_sent = send_mass_mail_from_template (
107177 recipients_to_send ,
108178 scenario .subject ,
109179 scenario .template_name ,
@@ -123,16 +193,36 @@ def status_callback(user, msg):
123193 )
124194 return 0
125195
126- MailingScenarioLog .objects .filter (
196+ pending_qs = MailingScenarioLog .objects .filter (
127197 scenario_code = scenario .code ,
128198 program = program ,
129199 scheduled_for = scheduled_for ,
130200 status = MailingScenarioLog .Status .PENDING ,
131201 user_id__in = user_ids ,
132- ).update (
133- status = MailingScenarioLog .Status .SENT , sent_at = timezone .now (), error = ""
134202 )
135- return len (user_ids )
203+ pending_count = pending_qs .count ()
204+ if pending_count :
205+ pending_qs .update (
206+ status = MailingScenarioLog .Status .FAILED ,
207+ error = "anymail_status missing" ,
208+ )
209+ failed_count += pending_count
210+ logger .warning (
211+ "Scenario %s program=%s pending left after send: %s" ,
212+ scenario .code ,
213+ program .id ,
214+ pending_count ,
215+ )
216+
217+ logger .info (
218+ "Scenario %s program=%s send_messages=%s sent=%s failed=%s" ,
219+ scenario .code ,
220+ program .id ,
221+ num_sent ,
222+ sent_count ,
223+ failed_count ,
224+ )
225+ return sent_count
136226
137227
138228@app .task
0 commit comments