@@ -83,6 +83,8 @@ def __init__(self):
8383 self ._bounce_events_fp = None
8484 self ._bouncecnt = 0
8585 self ._nextaction = time .time () + mm_cfg .REGISTER_BOUNCES_EVERY
86+ mailman_log ('debug' , 'BounceMixin: Initialized with next action time: %s' ,
87+ time .ctime (self ._nextaction ))
8688
8789 def _queue_bounces (self , listname , addrs , msg ):
8890 today = time .localtime ()[:3 ]
@@ -108,6 +110,9 @@ def _register_bounces(self, listname, addr, msg):
108110 filename = os .path .join (mm_cfg .BOUNCEQUEUE_DIR ,
109111 '%d.%d.pck' % (os .getpid (), now ))
110112
113+ mailman_log ('debug' , 'BounceMixin._register_bounces: Registering bounce for list %s, address %s' ,
114+ listname , addr )
115+
111116 # Write the bounce data to the pickle file
112117 try :
113118 # Use protocol 4 for Python 3 compatibility
@@ -116,19 +121,24 @@ def _register_bounces(self, listname, addr, msg):
116121 pickle .dump ((listname , addr , now , msg ), fp , protocol = 4 , fix_imports = True )
117122 # Set the file's mode appropriately
118123 os .chmod (filename , 0o660 )
124+ mailman_log ('debug' , 'BounceMixin._register_bounces: Successfully wrote bounce data to %s' , filename )
119125 except (IOError , OSError ) as e :
126+ mailman_log ('error' , 'BounceMixin._register_bounces: Failed to write bounce data to %s: %s\n Traceback:\n %s' ,
127+ filename , str (e ), traceback .format_exc ())
120128 try :
121129 os .unlink (filename )
122130 except (IOError , OSError ):
123131 pass
124132 raise SwitchboardError ('Could not save bounce to %s: %s' %
125133 (filename , e ))
126134 except Exception as e :
127- mailman_log ('error' , 'Error registering bounce: %s' , e )
135+ mailman_log ('error' , 'BounceMixin._register_bounces: Error registering bounce: %s\n Traceback:\n %s' ,
136+ str (e ), traceback .format_exc ())
128137 return False
129138
130139 def _cleanup (self ):
131140 if self ._bouncecnt > 0 :
141+ mailman_log ('debug' , 'BounceMixin._cleanup: Processing %d pending bounces' , self ._bouncecnt )
132142 self ._register_bounces ()
133143
134144 def _doperiodic (self ):
@@ -137,6 +147,8 @@ def _doperiodic(self):
137147 return
138148 # Let's go ahead and register the bounces we've got stored up
139149 self ._nextaction = now + mm_cfg .REGISTER_BOUNCES_EVERY
150+ mailman_log ('debug' , 'BounceMixin._doperiodic: Processing bounces, next action scheduled for %s' ,
151+ time .ctime (self ._nextaction ))
140152 self ._register_bounces ()
141153
142154 def _probe_bounce (self , mlist , token ):
@@ -174,89 +186,140 @@ class BounceRunner(Runner, BounceMixin):
174186 QDIR = mm_cfg .BOUNCEQUEUE_DIR
175187
176188 def __init__ (self , slice = None , numslices = 1 ):
177- Runner .__init__ (self , slice , numslices )
178- BounceMixin .__init__ (self )
189+ mailman_log ('debug' , 'BounceRunner: Starting initialization' )
190+ try :
191+ Runner .__init__ (self , slice , numslices )
192+ BounceMixin .__init__ (self )
193+ mailman_log ('debug' , 'BounceRunner: Initialization complete' )
194+ except Exception as e :
195+ mailman_log ('error' , 'BounceRunner: Initialization failed: %s\n Traceback:\n %s' ,
196+ str (e ), traceback .format_exc ())
197+ raise
179198
180199 def _dispose (self , mlist , msg , msgdata ):
181200 """Process a bounce message."""
182201 msgid = msg .get ('message-id' , 'n/a' )
183202 filebase = msgdata .get ('_filebase' , 'unknown' )
184203
204+ mailman_log ('debug' , 'BounceRunner._dispose: Starting to process bounce message %s (file: %s) for list %s' ,
205+ msgid , filebase , mlist .internal_name ())
206+
185207 # Check retry delay and duplicate processing
186208 if not self ._check_retry_delay (msgid , filebase ):
209+ mailman_log ('debug' , 'BounceRunner._dispose: Message %s failed retry delay check, skipping' , msgid )
187210 return False
188211
189212 # Make sure we have the most up-to-date state
190213 try :
191214 mlist .Load ()
215+ mailman_log ('debug' , 'BounceRunner._dispose: Successfully loaded list %s' , mlist .internal_name ())
192216 except Errors .MMCorruptListDatabaseError as e :
193- mailman_log ('error' , 'Failed to load list %s: %s' ,
194- mlist .internal_name (), e )
217+ mailman_log ('error' , 'BounceRunner._dispose: Failed to load list %s: %s \n Traceback: \n %s' ,
218+ mlist .internal_name (), str ( e ), traceback . format_exc () )
195219 self ._unmark_message_processed (msgid )
196220 return False
197221 except Exception as e :
198- mailman_log ('error' , 'Unexpected error loading list %s: %s' ,
199- mlist .internal_name (), e )
222+ mailman_log ('error' , 'BounceRunner._dispose: Unexpected error loading list %s: %s \n Traceback: \n %s' ,
223+ mlist .internal_name (), str ( e ), traceback . format_exc () )
200224 self ._unmark_message_processed (msgid )
201225 return False
202226
203227 # Validate message type first
204228 msg , success = self ._validate_message (msg , msgdata )
205229 if not success :
206- mailman_log ('error' , 'Message validation failed for bounce message' )
230+ mailman_log ('error' , 'BounceRunner._dispose: Message validation failed for bounce message %s' , msgid )
207231 self ._unmark_message_processed (msgid )
208232 return False
209233
210234 # Validate message headers
211235 if not msg .get ('message-id' ):
212- mailman_log ('error' , 'Message missing Message-ID header' )
236+ mailman_log ('error' , 'BounceRunner._dispose: Message missing Message-ID header' )
213237 self ._unmark_message_processed (msgid )
214238 return False
215239
240+ # Process the bounce message
216241 try :
217- # Log start of processing
218- mailman_log ('info' , 'BounceRunner: Starting to process bounce message %s (file: %s) for list %s' ,
219- msgid , filebase , mlist .internal_name ())
220-
221- # Process the bounce
222- if not self ._register_bounces (mlist .internal_name (), msg , msgdata ):
242+ mailman_log ('debug' , 'BounceRunner._dispose: Processing bounce message %s' , msgid )
243+ # Extract bounce information
244+ bounce_info = self ._extract_bounce_info (msg )
245+ if not bounce_info :
246+ mailman_log ('error' , 'BounceRunner._dispose: Failed to extract bounce information from message %s' , msgid )
223247 self ._unmark_message_processed (msgid )
224248 return False
225249
226- # Queue the bounce for further processing
227- try :
228- self . _queue_bounces ( mlist . internal_name (), msg , msgdata )
229- except Exception as e :
230- mailman_log ('error' , 'Error queueing bounces: %s' , e )
250+ # Register the bounce
251+ listname = mlist . internal_name ()
252+ addr = bounce_info . get ( 'recipient' )
253+ if not addr :
254+ mailman_log ('error' , 'BounceRunner._dispose: No recipient found in bounce message %s' , msgid )
231255 self ._unmark_message_processed (msgid )
232256 return False
233257
234- # Log successful completion
235- mailman_log ('info' , 'BounceRunner: Successfully processed bounce message %s (file: %s) for list %s' ,
236- msgid , filebase , mlist .internal_name ())
237- return True
258+ mailman_log ('debug' , 'BounceRunner._dispose: Registering bounce for list %s, address %s' , listname , addr )
259+ if self ._register_bounces (listname , addr , msg ):
260+ mailman_log ('debug' , 'BounceRunner._dispose: Successfully processed bounce message %s' , msgid )
261+ return True
262+ else :
263+ mailman_log ('error' , 'BounceRunner._dispose: Failed to register bounce for message %s' , msgid )
264+ return False
265+
238266 except Exception as e :
239- # Enhanced error logging with more context
240- mailman_log ('error' , 'Error processing bounce message %s for list %s: %s' ,
241- msgid , mlist .internal_name (), str (e ))
242- mailman_log ('error' , 'Message details:' )
243- mailman_log ('error' , ' Message ID: %s' , msgid )
244- mailman_log ('error' , ' From: %s' , msg .get ('from' , 'unknown' ))
245- mailman_log ('error' , ' To: %s' , msg .get ('to' , 'unknown' ))
246- mailman_log ('error' , ' Subject: %s' , msg .get ('subject' , '(no subject)' ))
247- mailman_log ('error' , ' Message type: %s' , type (msg ).__name__ )
248- mailman_log ('error' , ' Message data: %s' , str (msgdata ))
249- mailman_log ('error' , 'Traceback:\n %s' , traceback .format_exc ())
250-
251- # Remove from processed messages on error
267+ mailman_log ('error' , 'BounceRunner._dispose: Error processing bounce message %s: %s\n Traceback:\n %s' ,
268+ msgid , str (e ), traceback .format_exc ())
252269 self ._unmark_message_processed (msgid )
253270 return False
254271
255- _doperiodic = BounceMixin ._doperiodic
272+ def _extract_bounce_info (self , msg ):
273+ """Extract bounce information from a message."""
274+ try :
275+ # Log the message structure for debugging
276+ mailman_log ('debug' , 'BounceRunner._extract_bounce_info: Message structure:' )
277+ mailman_log ('debug' , ' Headers: %s' , dict (msg .items ()))
278+ mailman_log ('debug' , ' Content-Type: %s' , msg .get ('content-type' , 'unknown' ))
279+ mailman_log ('debug' , ' Is multipart: %s' , msg .is_multipart ())
280+
281+ # Extract bounce information based on message structure
282+ bounce_info = {}
283+
284+ # Try to get recipient from various headers
285+ for header in ['X-Failed-Recipients' , 'X-Original-To' , 'To' ]:
286+ if msg .get (header ):
287+ bounce_info ['recipient' ] = msg [header ]
288+ mailman_log ('debug' , 'BounceRunner._extract_bounce_info: Found recipient in %s header: %s' ,
289+ header , bounce_info ['recipient' ])
290+ break
291+
292+ # Try to get error information
293+ if msg .is_multipart ():
294+ for part in msg .get_payload ():
295+ if part .get_content_type () == 'message/delivery-status' :
296+ bounce_info ['error' ] = part .get_payload ()
297+ mailman_log ('debug' , 'BounceRunner._extract_bounce_info: Found delivery status in multipart message' )
298+ break
299+
300+ if not bounce_info .get ('recipient' ):
301+ mailman_log ('error' , 'BounceRunner._extract_bounce_info: Could not find recipient in bounce message' )
302+ return None
303+
304+ return bounce_info
305+
306+ except Exception as e :
307+ mailman_log ('error' , 'BounceRunner._extract_bounce_info: Error extracting bounce information: %s\n Traceback:\n %s' ,
308+ str (e ), traceback .format_exc ())
309+ return None
256310
257311 def _cleanup (self ):
258- BounceMixin ._cleanup (self )
259- Runner ._cleanup (self )
312+ """Clean up resources."""
313+ mailman_log ('debug' , 'BounceRunner: Starting cleanup' )
314+ try :
315+ BounceMixin ._cleanup (self )
316+ Runner ._cleanup (self )
317+ except Exception as e :
318+ mailman_log ('error' , 'BounceRunner: Cleanup failed: %s\n Traceback:\n %s' ,
319+ str (e ), traceback .format_exc ())
320+ mailman_log ('debug' , 'BounceRunner: Cleanup complete' )
321+
322+ _doperiodic = BounceMixin ._doperiodic
260323
261324
262325def verp_bounce (mlist , msg ):
0 commit comments