EximWan’t to pop off a quick e-mail on your laptop? Are you on a train, in a hotel, at a customer site, or at home? Depending on your location, you may want to use a distinct smart host for getting your e-mail off your device. Improving on an answer I gave on the Exim mailing-list the other day, I’d say a good solution to routing messages from a mobile device (in my case an Apple Mac Book Pro) is by using a queryprogram router.

As the documentation states, a queryprogram router

routes an address by running an external command and acting on its output. This is an expensive way to route, and is intended mainly for use in lightly- loaded systems

The word expensive refers to the “cost” of launching an external program, capuring and interpreting its output, but this “cost” is negligeable on a laptop because

  • modern systems have power enough anyway, and
  • the volume of mail sent from such devices is typically quite low.

The queryprogram router is very easy to describe in the Exim configuration file. I put mine quite far up on the list of routers, where I’d typically configure a smart host router:

      driver = queryprogram
      domains = !+local_domains
      command = /usr/exim/where-to '$local_part' '$domain'
      command_user = exim

When Exim evaluates this router, it runs the specified program /usr/exim /where-to, passing it the local-part (i.e. the bit before the @ character) and the domain portion of the e-mail address.

The program invoked by the queryprogram router must return a single line of text, which begins with ACCEPT, DEFER, FAIL, or any of the other keywords allowed. (Read the documentation.)

So, for example, if the where-to program returns a line containing the single word


Exim will defer the message – it will queue it and attempt to route it at a later time. (This keyword can be followed by an arbitrary text which is logged.)

If, on the other hand, Exim sees the line


it accepts the message for transport, passing it to the specified transport remote_smtp using the specified list of hosts, which in this case, is a literal IP address.

Another example line that can be returned by the where-to program used in the queryprogram router is:

ACCEPT TRANSPORT=smtp_auth HOSTS=smtp.gmail.com/MX LOOKUP=bydns

Here I return a different transport (one that uses outgoing SMTP AUTH for the target host) and I specify the HOSTS to be looked up in the DNS.

All this – and more – is part of a normal Exim installation if you have built it with


Let me now give you an example for the where-to program. I’m using a shell script to make it as simple as possible. The script will determine what “state” my laptop is in:

  • Am I connected to the Internet so I can use my default MTA for relaying messages?
  • Am I at a customer’s site and must use their gateway with SMTP AUTH?
  • Am I connected wirelessly?
  • Am I on my home network so I can use my SOHO MTA?

Depending on your infrastructure and environment, you may have to tweak how you go about deciding “where you are”.

    DEFERMSG="Don't know how to get there from here; deferring"
    TRANSPORT="remote_smtp"		# default transport
    function defer() {
    	echo "DEFER ${*:-$DEFERMSG}"
    case "${myhost}" in
    		defer "I'm offline";;
    		HOSTS="";;	# At home
    	x9001.megacorp.biz)			# At Cust
    		HOSTS="megacorp.biz/MX LOOKUP=bydns";;
    # If transport and hosts is set, accept the message
    if [ -n "$TRANSPORT" -a -n "$HOSTS" ]; then

In the example above, I’m checking the value of hostname only because that’s enough for me, but you can use whatever is best for you. I don’t use $LOCALPART nor $DOMAIN either, but you could to determine whether you should defer or route depending on the target domain; this could be used to avoid sending bulk messages to your account when you’re connected over and expensive Internet connection (e.g. UMTS).

Exim: that’s all.

Mail, Exim, Linux, Mobile, MacOSX, CLI, queryprogram, and location :: 03 Sep 2009 :: e-mail