User Tools

Site Tools


wormnet mail

marmot provides a multi-domain IMAP/SMTP mail service, powered by Exim and Cyrus IMAP.

All IPC with backend services (spamd, clamd, pgsql, lmtpd) is performed over unix domain sockets.

client configuration

Please use and for the IMAP (port 143) and SMTP (port 25 or 587) services.

Please use DIGEST-MD5, CRAM-MD5 or NTLM authentication, and username@domain as the username.

unexpunge / mail folder recovery

The Cyrus unexpunge command can unexpunge (and optionally undelete) any messages recently expunged. Also, deleting folders is really a rename into a special DELETED/ namespace. A nightly “expire” job purges all expunged messages and deleted folders after 30 days.

This is really a side-effect of the features' original design, to minimise the latency of user delete operations.

For example, to undelete everything you have expunged today, run the following as the cyrus user…

  cyrus@marmot:/$ /usr/lib/cyrus/bin/unexpunge -t1d user/ 
  restoring expunged messages in mailbox '!'
  restored 297 expunged messages

webmail ( might work if you're stuck behind a stoopid web filter). It uses HTTP Digest authentication, which is reasonably secure (although Basic auth could be spoofed by a MITM), but logging out can be a bit of a pain since browsers tend not to want to forget your credentials–so please consider this service beta at best.

The HTTP Digest authentication is backed by PostgreSQL; if you restart the database (eg for a security update) you'll need to do an /etc/init.d/apache2 graceful at the bare minimum for webmail to continue to work.

server-side filtering

There are two approaches:

  • simply use the username+folder@domain syntax; mail will automatically be delivered into INBOX/folder if it exists and has appropriate permission (in webmail: “Personal Settings” → Folders → folder → Sharing → Advanced → “+” → All users (anyone) → Post)
    • some web forms falsely think “+” is invalid in an e-mail address; “” (two hyphens) and “__” (two underscores) will be rewritten to “+
  • use SIEVE (there's a UI in webmail: the “Filters” tab in “Personal Settings”)

Please try to avoid client-side filters.

Managing sieve rules with text files

You can also write rules by hand and upload them when you're ready. Currently you can only do this locally like thus:-

$ sieveshell --authname='me@my.domain' --exec='put sieve-script' localhost
$ sieveshell --authname='me@my.domain' --exec='activate sieve-script' localhost

account creation

Enter the username, domain (“realm”) and password into the shadow table of the mail database on marmot.

If it's a new domain, please add it to the loginrealms line in /etc/imapd.conf on marmot.

Then use cyradm -u cyrus localhost on marmot (password in aformentioned shadow table) and issue “cm user/username@domain”. Then set an appropriate quota, eg sq user/username@domain STORAGE 100000.

shared mailboxes

A mailbox which does not begin user/ is not in an INBOX, but a shared mailbox. You can create them in cyradm with cm, as above, then use sam and lam to set and view appropriate permissions, eg:

localhost> lam admin/
anyone p lrswipkxtecd lrswipkxtecd

If, as in this example, you set anyone p, then Exim will deliver straight into that mailbox with e-mail address +admin/


This is governed by the alias table of the mail database on marmot. If there's an entry for a domain (realm), then Exim will treat the entire domain as local.

There are two booleans available (both defaulting to false) per alias:

  • suffixes: allow local_part+suffix (for an arbitrary suffix, which is stripped)
  • bulk: add a Precedence: bulk header to help stop auto-responders etc


The strategy is to be tolerant of standards-compliant MTAs which honour timeouts, use deliverable return-paths, aren't blacklisted etc etc

Greylisting is applied, but only in cases where dodginess is suspected, and then hints are sent to SpamAssassin. Most spam comes from zombies which never retry, so SpamAssassin shouldn't even need running.

Malware is rejected at SMTP time; a suitable SpamAssassin score (currently 5.0) will cause a rejection too. So will a dodgy attachment extension, or more general MIME-corruptness. However, even after a 550 after the DATA phase, Exim can store the message somewhere. This allows us to examine mail we've rejected :)

SpamAssassin Bayesian classifier training folders

Please note these as their filesystem locations below, suitable for cutting & pasting. Please ensure that ham folders only contain ham, and spam folders only spam. If you put something in the wrong folder, please delete it, expunge it and then ask postmaster to purge the expunged files.


sa-learn --ham --progress /var/spool/cyrus/mail/domain/j/{archive,projects/*}/*.


sa-learn --spam --progress /var/spool/cyrus/mail/domain/d/\:spam/*.
sa-learn --spam --progress /var/spool/cyrus/mail/domain/w/*.
sa-learn --spam --progress /var/spool/cyrus/mail/domain/j/*.
sa-learn --spam --progress /var/spool/cyrus/mail/domain/w/*.
sa-learn --spam --progress /var/spool/cyrus/mail/domain/w/*.


Any sender domain can be signed using DKIM. Choose a “selector” and record it in the dkim table:

INSERT INTO dkim VALUES ('', 'cat');

Then generate a keypair on marmot (1024-bit considered right in 2014; latterly 2048 suggested in RFC8301):

cd /etc/exim4/dkim
mkdir -m 750
openssl genrsa -out ${SELECTOR} 1024
openssl rsa -in ${SELECTOR} -out ${SELECTOR}.pub -pubout -outform PEM
chmod o= ${SELECTOR}*
echo "v=DKIM1; h=sha256; p=$(grep -vE '^\-\-\-' ${SELECTOR}.pub | tr -d '\n'); t=s;"

And finally mangle the public key into a DNS TXT record. See here for some tweakables.

_adsp._domainkey IN TXT "dkim=all;"
cat._domainkey   IN TXT "v=DKIM1; h=sha256; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCzl70kXqRENAgRfWRZ2WyvLtdQe22E1OvZMgIAwPV8GHraN2z0YCXgkeO7DW5t/0sOOa9z/hOmASTilds0oo2qgCmcJwV/YzGNAY0nw1CWAawIr5LlkLGzrLwvSv69iMsQJlsHMbqij0ljQpVuJ+DY5S0FYsgMlnyYWgE4EmEL5wIDAQAB; t=s;"

key rotation

Just make a new keypair (with a new name) / and associated TXT record. Then UPDATE your row in the dkim table. The old TXT record can be deleted after a week.

People seem to think rotating keys quarterly is a good idea.

Allowing mail relaying from particular hosts

It may be useful to allow home gateways, for example, to relay mail via. marmot. The configuration for this is in the relay_host table.


Mail on wormnet is provided by the following Debian packages (where a * denotes a backport from testing or unstable or experimental):

  • exim4-daemon-heavy* (MTA) (need to hack the debian/control file to change build dependency from libdb5.1-dev to libdb4.8-dev, and the debian/rules file to uncomment OPENSSL:=1)
    • clamav-daemon (antivirus)
    • spamassassin (main anti-spam thing, plus lots of friggery)
  • cyrus-imapd-2.4* (IMAP server) (need to hack the debian/control file so that cyrus-common doesn't depend on db-util or db5.1-util)
  • libsasl2-modules-sql (accounts, passwords)
    • postgresql-8.4
      • postgresql-contrib-8.4 (for the pgcrypto functions for generating HTTP Digest hashes)
  • roundcube-core* (webmail)
    • roundcube-plugins-extra* (for UI for sieve rules)
mail.txt · Last modified: 2019/09/29 16:34 by mb