Skip to content

Process monthly membership reminder bounces against member lists.#39

Open
jaredmauch wants to merge 1 commit into
mainfrom
monthly_bounce_processing
Open

Process monthly membership reminder bounces against member lists.#39
jaredmauch wants to merge 1 commit into
mainfrom
monthly_bounce_processing

Conversation

@jaredmauch

Copy link
Copy Markdown
Owner

Site list bounces were previously forwarded to admins without scoring. Register reminder bounces on each subscribed list that sends reminders, while still forwarding owner moderation notices unchanged.

Site list bounces were previously forwarded to admins without scoring.
Register reminder bounces on each subscribed list that sends reminders,
while still forwarding owner moderation notices unchanged.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR changes bounce handling so that bounces generated by monthly membership/password reminders sent from the site list can be scored against the member’s subscribed lists (instead of being forwarded to site admins without processing), while keeping owner-moderation notice forwarding unchanged.

Changes:

  • Add detection for “membership reminder” bounces and route them into per-list bounce event registration.
  • Add a new config flag (BOUNCE_PROCESS_REMINDER_BOUNCES) and mark reminder messages with X-Mailman-Membership-Reminder: yes.
  • Add a targeted unit test module for reminder-bounce detection and queuing behavior.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.

File Description
tests/test_bounce_reminders.py Adds tests for reminder-bounce classification and queuing behavior.
Mailman/Queue/BounceRunner.py Implements reminder-bounce detection and queues reminder bounces against member lists.
Mailman/Defaults.py.in Introduces BOUNCE_PROCESS_REMINDER_BOUNCES default configuration and updates related comments.
cron/mailpasswds Adds a marker header so reminder messages can be reliably identified when they bounce.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +25 to +38
SAMPLE = os.path.join(
_TESTDIR, 'bounces', 'samples_from_messages',
'sample_01_undelivered_mail_returned_to_sender.eml')



class ReminderBounceTest(unittest.TestCase):
def test_membership_reminder_sample(self):
if not os.path.exists(SAMPLE):
self.skipTest('sample bounce file not available')
with open(SAMPLE, 'rb') as fp:
msg = email.message_from_binary_file(fp)
self.assertTrue(is_membership_reminder_bounce(msg))

Comment on lines +113 to +126
runner._bounce_events_fp.seek(0)
events = []
while True:
try:
events.append(pickle.load(runner._bounce_events_fp))
except EOFError:
break
self.assertEqual(len(events), 1)
self.assertEqual(events[0][0], 'mylist')
self.assertEqual(events[0][1], 'user@example.com')
runner._bounce_events_fp.close()
os.unlink(runner._bounce_events_file)
runner._bounce_events_fp = None
runner._bouncecnt = 0
Comment on lines +79 to +81
# their lists. So now we ignore most site list bounces. Membership
# reminder bounces can optionally be processed; see
# BOUNCE_PROCESS_REMINDER_BOUNCES.
Comment on lines +310 to +329
def is_membership_reminder_bounce(msg):
"""Return true if this bounce is for a monthly membership reminder."""
for part in typed_subpart_iterator(msg, 'message', 'rfc822'):
orig = part.get_payload(0)
if orig is None:
continue
if orig.get('X-Mailman-Membership-Reminder', '').lower() == 'yes':
return True
if orig.get('x-list-administrivia', '').lower() != 'yes':
continue
sender = parseaddr(orig.get('from', ''))[1].lower()
if not sender:
continue
# Owner notifications are sent from the site -bounces address.
if _is_site_bounces_address(sender):
continue
subj = Utils.oneline(orig.get('subject', ''), 'us-ascii').lower()
if 'reminder' in subj:
return True
return False
Comment on lines +103 to +117
def _queue_reminder_bounces(self, addr, msg):
"""Queue a reminder bounce for each subscribed list that sends reminders."""
for listname in Utils.list_names():
if listname.lower() == mm_cfg.MAILMAN_SITE_LIST.lower():
continue
mlist = MailList(listname, lock=0)
if not mlist.bounce_processing:
continue
if not mlist.send_reminders:
continue
if not mlist.isMember(addr):
continue
if mlist.getMemberOption(addr, mm_cfg.SuppressPasswordReminder):
continue
self._queue_bounces(listname, [addr], msg)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants