In some setups, mail to several different mail addresses are routed into the same roundup instance.
This works very well with the exception that a user with the mail address the mail was destined for is created and then added to the nosy list, which means that every change note will be sent not only to the people that are interested, but also the tracker itself. That's kind of ugly.
The recommended solution is to create an auditor that checks if the user that corresponds to the recipient address is on the nosy list, and then removes it from the nosy.
Here is just such an auditor, contributed by "Kyle Lanclos":http://www.ucolick.org/~lanclos/. This auditor has been tested with Roundup 1.3.2::
# Prevent specific roundup usernames from appearing in an issue's nosy list. # The value designated as 'email' in the config.ini is already omitted # from the nosy list, but any aliases for the same will be treated as # regular roundup users. # # # # Definitions. # # # # Define a python list of user names (note: NOT e-mail addresses, and # NOT user ids) to omit from the nosy list. #omit_user_list = ['trackeralias','anotheralias'] omit_user_list = [] # Set DEBUG to True to get debug output to a file. DEBUG = False if DEBUG: debug_log_filename = '/tmp/nosyauditor.log' debug_log_filemode = 0666 # # # # End of definitions. No changes should be required below this point. # # # # # # # Required modules. # # # # no imports required. # # # # Function definitions. # # # def intStringSort (string_int1, string_int2): ''' Take two strings representing integers, and perform a standard integer comparison. ''' int1 = int(string_int1) int2 = int(string_int2) if int1 > int2: return 1 if int1 < int2: return -1 return 0 def validateNosyUsers (db, cl, nodeid, new_values): ''' Remove any unwanted usernames (as designated above in omit_user_list) from the old + new nosy lists, if any. ''' if DEBUG: import os debug_log_file = open (debug_log_filename, 'a') os.chmod (debug_log_filename, debug_log_filemode) # nodeid will be None if this is a new issue if nodeid == None: old_nosy_list = [] else: # Populate the old_nosy_list from the existing # issue information. Explicitly make a copy of # the old list, to avoid unnecessarily modifying # the old values. old_nosy_list = list (cl.get (nodeid, 'nosy')) # Acquire the new nosy list, if any. Explicitly make a copy # of the new list, to avoid unnecessarily modifying the new # values. if new_values.has_key('nosy'): # The new nosy list is all we care about if it is # being actively modified. new_nosy_list = list (new_values.get ('nosy', [])) full_nosy_list = new_nosy_list else: # If the nosy element is not being modified, # initialize the full list from the old nosy list. new_nosy_list = [] full_nosy_list = old_nosy_list # Don't assume that these lists are sorted; if they are # not properly sorted, the comparison at the end of the # function may fail. full_nosy_list.sort (intStringSort) if DEBUG: debug_log_file.write ("Old nosy list: %s\n" % (old_nosy_list)) debug_log_file.write ("New nosy list: %s\n" % (new_nosy_list)) debug_log_file.write ("Full nosy list: %s\n" % (full_nosy_list)) # Determine a username -> userid mapping for entries in omit_user_list. omit_userid_list = [] for omit_username in omit_user_list: userid_list = db.user.stringFind (username=omit_username) omit_userid_list = omit_userid_list + userid_list if DEBUG: debug_log_file.write ("Translated '%s' to user id '%s'.\n" % (omit_username, userid_list)) omit_userid_list.sort (intStringSort) if DEBUG: debug_log_file.write ("User IDs to omit: %s\n" % (omit_userid_list)) # Check our complete full_nosy_list for usernames in the # omit_user_list list. checked_nosy_list = [] for nosy_userid in full_nosy_list: if nosy_userid in omit_userid_list: if DEBUG: debug_log_file.write ("Omitting user id '%s'.\n" % (nosy_userid)) pass else: checked_nosy_list.append (nosy_userid) if DEBUG: debug_log_file.write ("Validated nosy list: %s\n" % (checked_nosy_list)) # If the validated list is not the same as what's being processed # in this request, update the list. if full_nosy_list != checked_nosy_list: new_values['nosy'] = checked_nosy_list if DEBUG: debug_log_file.close() # End of validateNosyUsers # # # # Required hooks for roundup auditors. The third # argument is the priority; note that we are explicitly # requesting non-standard priorities. # # The first pass at priority 90 catches any bad usernames # before the nosy detectors run at default priority (100); # this prevents the detector from sending e-mails users already # on an issue's nosy list, but were recently added to the # omit list above. # # The second pass at priority 110 cleans up any bad usernames # that may have been added to the nosy list by the nosy detector # itself; for example, a receipient on the To: line of an # initial message for an issue (if your roundup is configured # to add such users to the nosy list). # # # def init(db): db.issue.audit('create', validateNosyUsers, 90) db.issue.audit('set', validateNosyUsers, 90) db.issue.audit('create', validateNosyUsers, 110) db.issue.audit('set', validateNosyUsers, 110)