Skip to content

Commit 937c9b5

Browse files
committed
update
1 parent 21858ec commit 937c9b5

6 files changed

Lines changed: 888 additions & 418 deletions

File tree

Mailman/Queue/BounceRunner.py

Lines changed: 103 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -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\nTraceback:\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\nTraceback:\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\nTraceback:\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\nTraceback:\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\nTraceback:\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\nTraceback:\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\nTraceback:\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\nTraceback:\n%s',
319+
str(e), traceback.format_exc())
320+
mailman_log('debug', 'BounceRunner: Cleanup complete')
321+
322+
_doperiodic = BounceMixin._doperiodic
260323

261324

262325
def verp_bounce(mlist, msg):

0 commit comments

Comments
 (0)