Web Interface to procmail ??
Postfix / Dovecot side of things I think I can handle, but it would be nice to offer a web interface to procmail to handle server side basic filtering of incoming mail (users will NOT be given shell access). Procmail is what I personally use, and works best because it doesn't matter what client I connect with, the messages go where they are suppose to go.
I can code my own basic interface, but if one already exists, that would be better since it (hopefully) will already have been through testing / bug squashing. Anyone know of one?
The way I probably do it is to store the filtering information in XML that the web app modifies, and then use background process perl or php-cli to validate the XML and write a fresh .procmailrc upon modification of the XML by the web app, so the app doesn't need to execute command or have write permission to the .procmailrc - but if something like this already exists, I'd love to know.
4 Replies
class Recipe:
user = models.ForeignKey(User) # the recipe belongs to this user
order = models.IntegerField() # sort order for this recipe
flags = models.CharField() # flags; could probably go to town with a M2M field or something, too
action = models.TextField() # exactly one action line
@property
def block(self):
"Returns a configuration stanza appropriate for .procmailrc"
recipe = (":0 %s\n" % self.flags) if self.flags else ":0\n"
for condition in self.condition_set.all():
recipe += "* %s\n" % condition
recipe += self.action + "\n"
return recipe
class Condition:
condition = models.TextField() # the regexp to match
recipe = models.ForeignKey(Recipe) # the condition belongs to this recipe
# instantiated like:
my_recipe = Recipe.objects.create(
user = User.objects.get(username='jboehner')
order = 10 # like MX records ;-)
flags = 'c' # generate a carbon copy
action = '! president@whitehouse.gov' # forward to POTUS
)
my_recipe.condition_set.create(
condition = "^From: vicepresident@whitehouse.gov" # match that sneaky under-the-table-dealin' joe
)
Then simply, as a user that can write to all of these locations:
from models import User, Recipe
for user in User.objects.filter(recipes_set__count__gt=0):
with open('%s/.procmailrc' % user.homedir, 'w') as fp:
for recipe in Recipe.objects.filter(user=user).order_by('order'):
fp.write(recipe.block)
And bam, out they come. Apologies for the Django-specificness here; it was the easiest way to bang this out in a hurry. Testing, error handling, user interfacing, not writing out all the .procmailrc files every time this runs, the inevitable race conditions, and all that other stuff are left as an exercise for the reader.
I think Webmin has a module that does this – it might be worth looking through its source for inspiration, too.
I doubt lots of reads and writes are an issue here, most people who even make use of server side filtering will alter their filtering less than once a week, XML is excellent for file based data storage that doesn't change often, and most scripting languages have tools specifically designed to extract the needed info from it.
I get the feeling PHP generally doesn't make database access easy, which probably changes the equation significantly. In any case, use the tools you got.
I just don't like to use them where flat file seems better (cases when relational queries and speed aren't necessary) - especially if/when I need to move accounts around from one server to another.