Mailman is a tried-and-tested Open Source mailing list manager. It's robust and reasonably efficient when running, however it organises lists internally by their local name only. In other words, you can't have one list called maillist@domain.org on the same server as another list called maillist@somewhereelse.com on the same machine, unless you have a separate mailman installation for each domain.
Many production environments do appear to use the separate installation per domain approach, however with 8 'queue runner' processes running per installation, it would not require many domains before mailman starts gobbling unacceptable levels of resources.
One solution is to internally combine the domain name and the list name selected by the user. This would mean that each list would appear to the user as listname@domain.com, but internally would be listname-domain.com@domain.com.
In order to pull this off transparently, the following needs to be accomplished:
email aliases:
The address {listname}@mydomain.com needs to be aliased to {listname}-{domain}@mydomain.com so that incoming mail for the list is delivered correctly
mailing list archives:
Some public web address such as www.domain.com/mailarchive/{listname} should be redirected to www.domain.com/pipermail/{listname}-{domain}
list creation:
a mechanism that prevents lists being created with a hyphen in the name (or whatever other character is used as a separator)
Outgoing email messages:
need to be changed so that email addresses and listnames in them appear in the 'friendly' format
There's a good synopsis of the basics of Python syntax at
this site, which is quite suitable for experienced programmers wanting a quick overview, despite its name. IBM also provide
a good primer.
Like in C, strings are really just character arrays. Thus you can refer to a single character of a string using array notation, such as
somestring[5]. Python adds to this standard array notation with the concept of slicing, where two indicies are supplied, separated by a colon. This creates a new array consisting of the elements between the two indicies. When dealing with strings, the slice is the Python way of specifying substrings e.g.
somestring[5:8].
Python does use a lot of syntax that's quite different to other programming languages such as C++ or Java. For instance, to indicate that a class is derived from another class, we simply add the name of the base class in parenthesis after the name of the derived class. The derived class can override member functions of the base class.
One thing in Python which we need to get our head round for these virtual domain script changes is the Python dictionary type:
UserDict. This is really just a class wrapper for the built-in dictionary type, allowing classes to inherit from it to override or add methods and data attributes. (In Python, class member variables are known as
data attributes.) Use of this
UserDict wrapper class has been largely obviated in newer versions of Python by the ability to inherit directly from the built-in dictionary type using the keyword
dict as the class name; however the mailman scripts use the older syntax.
The dictionary type is in effect an associative array, i.e. a list of name-value pairs. The
UserDict class defines a single data attribute (cunningly called 'data'), which is underlying dictionary data structure of the class.
Here's the standard Python way to use a dictionary to replace tokens in a string of text:
template_string = 'foo %(sometoken)s bar %(sometoken)s baz'
message = template_string % {'sometoken': variable}
This is exactly what the
SafeDict.interpolate() method does:
def interpolate(self, template):
return template % self
compton
1:22 pm, Tuesday, 22 September 09
Script changes:
Here are the required changes, in principle. The assumption here is that some external script/web-page appends the domain name to the beginning of the listname before the list is created. We thus only need to change how the listname is output for display.Note that this code does not check if the listname does indeed contain a hyphen, but this is not a problem because the -1 returned by find() will simply cause the full internal listname to be returned by the slice. This is because the slice [0:-1] is interpreted as the slice from the first character (zeroth) to the character with index one less than the string length, i.e. the last character.
Mailman/MailList.py
- in various places, self.internal_name() is used to get the mailing list name, sidestepping the above fix. Such instances could be swapped for self.getListAddress(self).
In many places, self.real_name (where self is an instance of MailList) is used to get the name - rather than the email address - of the list. This could be replaced with self.real_name[0:real_name.find('-')].
Perhaps quicker but slightly more kludgy would be to change Utils.maketext() so that any tokens called listname are truncated at the hyphen. To do this, we need to change the SafeDict.__getitem__() method defined at line 31: