% The Postoffice SMTP server % David Parsons % Tue Jan 15 15:43:43 PST 2008 #Postoffice [Postoffice](class:caps) is a simple SMTP mail server and client. I wrote it for pell because spam was getting out of control and I would rather write my own mail service than continue to hack up `sendmail` for antispammery. [Postoffice](class:caps) provides a [greylist](http://projects.puremagic.com/greylisting) to slow down the rate of incoming spam, and can be configured to do antivirus checking on incoming mail either via the [sendmail](http://www.sendmail.com) [milter] (http://cvs.sourceforge.net/viewcvs.py/*checkout*/pmilter/pmilter/doc/milter-protocol.txt?rev=1) protocol or a traditional hardcoded AV program. [Postoffice](class:caps) can be configured to deliver mail to accounts inside [vm-pop3d](http://www.reedmedia.net/software/virtualmail-pop3d/)-style virtual domains, and it can further be enabled to support **`AUTH LOGIN`** for people inside virtual domains, so they can use [postoffice](class:caps) as a mail forwarder when replying to mail (I've also written some [virtual domain utility programs](/~orc/Code/post/) to go along with the virtual domain code in [postoffice](class:caps) and vm-pop3d.) [Postoffice](class:caps) accepts (and ignores) many of the same command line options that are passed to `sendmail`, and it comes with the usual crop of `sendmail` compatable aliases; `runq`, `mailq`, `newaliases`, and `sendmail`. ##Additional Documentation Pierre-Philipp Braun at nethence has written [documentation](http://www.nethence.com/postoffice) on how to run [postoffice](class:caps) on a non-ia32 [NetBSD](http://www.netbsd.org) box. ##Source Code =[version 1.4.9](postoffice-1.4.9.tar.gz)= **`AUTH LOGIN`** was not working, because the `Username:` string was being uppercased during message writing and, in addition, domain 0 handling wasn't working inside `auth.c`. 1.4.9 corrects this defect and makes [postoffice](class:caps) work better with networked mail clients. =[version 1.4.8](postoffice-1.4.8.tar.gz)= 1.4.8 adds no features, but fixes a couple of problems when trying to build with Xcode on macos 10.5; 1. INT_MAX is no longer found in the twisty maze of include files [postoffice](class:caps) uses, so I had to add `` to the offending modules. 2. In `AC_SUB`, blank expansions were coming out as `^?`, which is not what I had in mind. Macos uses the gnu `sh` clone instead of a real Bourne shell, and that was having `echo ${@}` expand to `^?` inside the shell? Okay, colo(u)r me confused, but I fixed it, I think. (there is no 1.4.7; I bobbled the version#s and skipped a number) =[version 1.4.6](postoffice-1.4.6.tar.gz)= 1.4.6 adds a new configuration option -- `trusted=`_hostname_, which tells [postoffice](class:caps) to treat _hostname_ as if it was localhost. In addition, I've tweaked the mx getter so that if you set `localmx`, you need to to explicitly set the MX for the remote machine before it's treated as localhost. On the bugfix front, when I went in and attempted to make `gcc -Wall` quieter, I managed to break builds without the milter code enabled. So 1.4.6 fixes that. =[version 1.4.5c](postoffice-1.4.5c.tar.gz)= This version sweeps some of the grottier parts of the milter interface up into tidy stub functions, plus changes the way [postoffice](class:caps) handles **`RCPT TO:`** before **`MAIL FROM:`**; it used to spit out a **`501`** error before it dropped the address, but it now returns a **`250`** before it drops the address. I'm willing to do this because of the milter problem I corrected in [[postoffice](class:caps) 1.4.0](#1.4.0) -- since some common milters (spamassassin, clamav) drop into an infinite loop when they get **`RCPT TO:`** before **`MAIL FROM:`**, that means that it never happens under the higher-priced brand and so I won't have to worry about legitimate mail tripping over this feature. =[version 1.4.5a](postoffice-1.4.5a.tar.gz)= 1.4.5a finished the project to make it so that you can configure it with ``CC=`gcc -Wall` `` and get a clean build without errors. The code changes are gross (and inefficient, and quite possibly bugridden,) but now stupid gcc will pass them right on by without complaint. =[version 1.4.5](postoffice-1.4.5.tar.gz)= 1.4.5 fixes a minor bug (`spam=bounce` wasn't setting spam=bounce; this was reported by Bob Dunlop, who was evaluating [postoffice](class:caps) for inclusion in an ARM-based system)) and has a fairly extensive code scrub to sweep out things that the FSF's so-called "C" compiler complains about. Some of this was simply housekeeping (I added a configure check for the `volatile` keyword, then plastered `volatile` prefixes on everything that gcc complained about in functions containing `setjmp`/`longjmp`; on systems that don't support volatile it `#defines` that keyword to an empty comment,) some involved some minor code rework (forcing an assignment to a variable that wouldn't be set if a loop failed; previously I was failing the condition when `loop counter`==max,) and some involved tweaking configure to disable the stupid warning (I combine assignments and tests by doing `if ( var = setter() )`, and gcc whines bitterly about this unless I change my coding style or append `-Wno-parentheses` to **`CFLAGS`**. I'm not going to change my coding style after 30 years of programming, so I have changed **`CFLAGS`** instead.) =[version 1.4.4](postoffice-1.4.4.tar.gz)= 1.4.4 adds [`spam=`](#1.4.3a)-like configuration options to manage connections from blacklisted sites similar to how spam-ridden messages are currently handled. Like `spam=`, `blacklist=` supports `bounce`, `accept`, and `file` options, which work much like they work with `spam=` =spam=bounce= Refuse connections from blacklisted hosts (this is the default.) =spam=accept= _Accept_ connections from blacklisted hosts. Aside from getting a **REJECT** message in syslog, this is as if you didn't have any blacklisting at all. =spam=file:_folder_= Accept connections from blacklisted hosts, but drop all (local) mail from those hosts into a blacklist folder. The format of the folder name is identical to `spam=folder`, with a `~/` prefix meaning a folder in the user's home directory, otherwise a folder in the mailspool. =[version 1.4.3b](postoffice-1.4.3b.tar.gz)= 1.4.3b contains one tiny bugfix that corrects an annoying (but not, as far as I can tell, fatal) error; when a message is initially passed into [postoffice](class:caps), it is scanned to see if it contains a `Date:`, `Message-ID:`, or `From:` header. If it does not, those headers are generated and placed into the additional headers section of the control file. The bug is that [postoffice](class:caps) _didn't bother to ever check the additional headers section_ for those required headers, and would thus add a new copy of the originally missing headers every time a queuerun would happen. If you're attempting to send mail to a site that refuses to accept it, the additional headers section will grow without bound. It's a dumb coding error, but by the simple expedient of pulling the header scanner into a separate function I could fix it without causing too much additional code bloat. =[[version 1.4.3a](postoffice-1.4.3a.tar.gz)](id:1.4.3a)= 1.4.3a revises the `junkfolder=` feature that I introduced in [1.4.3](#1.4.3); I've renamed the setting to `spam=`, which can now take three values: =bounce[:why]= Bounce the spam (the traditional -- and default -- behavior.) `why` is an optional reason that you can give (one line only) for bouncing the spam-infested mail. =accept= Treat the spam-infested message as a regular mail message. The only way to automatically tell that it's a spam-infested message is that [postoffice](class:caps) adds an `**X-Spam:**` header to the message that contains the diagnostic message from the milter or av program. If the incoming message already contains an `X-Spam` header, that header will _not_ be removed. =folder:path= This is what `junkfolder=` has become. And the behavior of `spam=folder` has slightly changed here; **local** users will have their spam-infested mail delivered to the spamfolder, but remote (and virtual domain) users will have the spam delivered as if the setting was `spam=accept`. `Spam=folder` is now a fancy enhancement to `spam=accept` that doesn't require every user to use procmail to weed out the X-Spam'med messages. The folder format is slightly different. There are now two types of valid path: 1. `**~/**path`, which writes the spam to the folder `path` in the users home directory. `path` can be anything (it's treated like a `/path` in a .forward file), so the restrictions on file redirections apply here. 2. `suffix`, which writes the spam to the folder _username_**:**`suffix` in the mail spool directory. If you're using imap, this might be a better solution than writing the spam to the users home directory, though the usual caveats about the file growning without bound still apply. As an extra treat, I've actually documented the spam= option now. =[[version 1.4.3](postoffice-1.4.3.tar.gz)](id:1.4.3)= 1.4.3 introduces one new feature; if you set the config file option `junkfolder=`, unwanted mail will not be bounced but will instead be put into a junkmail folder named <user>:<junkfolder>. This is a first release of this feature, implemented in a hurry because I needed to change my spamcatching behavior so I could catch spamalike mail coming in from my relatives. As an artifact of the hasty release, there is no documentation other than what's written here. It's possible that the functionality will alter over the next few weeks, but if you desire adventure this is the software release for you. =[version 1.4.2a](postoffice-1.4.2a.tar.gz)= No new features, no new bugfixes, but I've switched to [git](http://git.or.cz) for my SCCS, so I wanted to publish a warning release to see if the new version control system will end up eating my brane. =[version 1.4.2](postoffice-1.4.2.tar.gz)= No new features in this one, just bugfixes: 1. the am64 ubuntu port ran into a debug statement where I didn't wrap a pair of `vfprintf()`s in `va_start`/`va_end`, but spread them around both of them. On the 32 bit Linuxes I've installed on this doesn't make a difference, but the 64 bit world is, um, different. Ooops. 2. the other bug was the half-expected rebreaking on MacOS support. Despite having a macbook (which I am even now typing these release notes into), I hadn't actually bothered to get my own copy of XCode and didn't test the resolver detection changes for MacOS on a MacOS system. Ooops(2). =[version 1.4.1](postoffice-1.4.1.tar.gz)= 1.4.1 fixes some of the bugs that were in 1.4.0, adds missing features (and the missing manual page for `usermap(7)`,) and has been tweaked so that it builds on another linux variant (ubuntu on an am86 machine.) ####New features 1. Adds the usermap target ~, which is the username matched by a ~ in a usermap pattern. 2. Allows multiple usermaps. 3. List usermaps as part of the SMTP **DEBUG** output. 4. The missing `usermap(7)` manpage. ####Bugfixes 1. Does case-insensitive matching when reading a personal alias file (the Lego shop-at-home website [UPPERCASES](class:caps) all user names, so **`SATH-ORC`** was not matching the sath-orc entry in my ~/.alias file. Ooops.) 2. Use the new function `AC_CHECK_RESOLVER` (in [configure.sh](http://www.pell.portland.or.us/~orc/Code/configure/)) to look for the presence of the Berkeley resolver library. This code attempts to autodetect the broken [Darwin](http://en.wikipedia.org/wiki/Darwin_(operating_system)) resolver library (Darwin, being essentially a FreeBSD branch, has library interfaces that mutate just as fast as gl\*bc does. Using `BIND_8_COMPAT` is only a temporary patch, and I'll probably have to switch to the djbdns client library to get a more-stable replacement for `res_query()`,) so it may break Darwin anew. 3. Lots and lots of code cleanup to remove unused variables and add missing headers. The resolver library detection fix and the code cleanup was because of a bug report from Wink Saville, who tried to build [postoffice](class:caps) on a 64-bit [ubuntu 7.04](http://www.ubuntu.com/) machine. The resolver library wasn't detected because there doesn't appear to be a `res_query()` in glibc 2.8 (it's a `#define` for `__res_query()`. Ugh,) then, after I tweaked configure.inc so that it would actually DETECT the resolver, it dumped core because I didn't include <time.h;> before using `strftime()` [`sizeof(time_t)` != `sizeof(int)` on an am64 machine] so I had to go on a binge of adding the appropriate `#include`'s to circumvent any [all-the-world's-a-VAX](http://www.lysator.liu.se/c/ten-commandments.html)'isms that were in the code. (There are still quite a few implicit global functions inside [postoffice](class:caps), but those are functions that return small scalars (I'm not _overly_ worried about what happens when a message gets more than 2^31 unique recipients on it; I suspect that by that time the machine would be so far into swap that the heat death of the Sun would happen before it finished processing the headers.) =[[version 1.4.0](postoffice-1.4.0.tar.gz)](id:1.4.0)= 1.4.0 introduces the new feature of _usermaps_, which are a way to let users have temporary mail addresses which they can use when they deal with possible spammers. A usermap is simply a personal alias file (formatted like the `aliases(5)` file) which is placed in a home directory, and which is referred to by a `usermap` option in `postoffice.cf(5)`. The `usermap` option is formatted as _pattern_:_target_{,_target_}; the pattern is a shell-style wildcard, with the addition of using the **~** to match any valid user in the domain. A match is either an alias or the special token **~/filename**, which is the address of a personal alias file. When a usermap is called, [postoffice](class:caps) will try each _target_, stopping when it matches one. > For example, the usermap **\*-~**:**~/.alias**,**bounce** will > match any mail address of the format _something_-_user_. If > it matches an address, [postoffice](class:caps) will first > see if the address is in **~user/.alias**, and then if it doesn't > find a match there it will map to the fixed address **bounce**. There are also a couple of trivial bugfixes in 1.4.0 1. [Postoffice](class:caps) wraps smtp sessions in several layers of timeout. There were some cases where an alarm would fire when the default signal catcher was running, so you'd end up with core dump and a crash warning for a completely normal timeout. 2. A second, and more annoying, bug was discovered when testing the new usermap code. [Postoffice](class:caps) is fairly relaxed about the order of **`MAIL FROM`** and **`RCPT TO`** commands and will accept them in any order as long as both of them have been issued when a **`DATA`** command arrives. But some of the sendmail filters (milters) I use are not so forgiving, and if they get a **`RCPT TO`** prior to a **`MAIL FROM,`** they will freeze and lock the mail session. This is bad programming, to say the least, but it's broken in a sendmail-compatable fashion so it's not likely that it will ever change. So I've crippled postoffice (if built with `--with-milter`) to whine bitterly about **`RCPT TO`** without a prior MAIL FROM.
  • A super-trivial bugfix is a tweak to configure.sh to test for the existance of `malloc.h` so I can only include it on machines that actually have it. This is a generalization of the **`OS_DARWIN`** support that Andras Salamon contributed for 1.3.8c, and should make the code a little bit more portable to other machines that use C compilers that blindly follow the whims of the (break-all-of-the-)standards committees. ->[Older versions of the code](older.html) are still available.<-