HOWTO: Using outgoing BSMTP with Exim

I recently had the interesting issue of being in a location where I had outgoing ssh access but not access to outgoing SMTP, but wished to send email from my laptop (running Debian) using mutt. The following explains the steps I took to be able to send email via another machine.

Configuring exim

I am running exim version 4.69-6 with the standard Debian configuration. I decided to use BSMTP as I do not have (nor do I particularly wish to have) a webmail account. My hosts did not allow access to outgoing SMTP servers, and I did not have root access to any other machine at that point to be able to tunnel through it.

I started by modifying my exim configuration as follows. I did not want to lose my existing configuration, so I created a replacement for /etc/exim4/conf.d/router/200_exim4-config_primary called /etc/exim4/conf.d/router/200_exim4-config_primary.rul (Debian's exim package is set up to read a .rul file in place of the corresponding standard file, allowing for temporary overwrites). This file is identical to the original one, except for the smarthost part; I replaced the lines

  transport = remote_smtp_smarthost
  route_list = * DCsmarthost byname
  host_find_failed = defer
  same_domain_copy_routing = yes


  transport = batchsmtp_appendfile
  route_list = * batched.hosts

So I now require a transport called batchsmtp_appendfile. I therefore created a file called /etc/exim4/conf.d/transport/40_exim4-config_batchsmtp_appendfile containing the following code:

### transport/40_exim4-config_batchsmtp_appendfile

# This transport is used for batching messages using BSMTP when a
# smarthost is unavailable.

  debug_print = "T: batchsmtp_appendfile for $local_part@$domain"
  driver = appendfile
  directory = /var/spool/exim4/bsmtp
  batch_max = 100
  user = Debian-exim

(Note that it is modelled on the smtp transport code.) This places all of my outgoing non-local emails into files in the directory /var/spool/exim4/bsmtp. So the next thing is to create this directory and to ensure that the Debian-exim user has write access to it. (The easiest way to do this is to chown Debian-exim:Debian-exim /var/spool/exim4/bsmtp and then chmod 750 ... it.

Now you need to reconfigure exim: run update-exim4.conf.template --run if you are using a monolithic configuration file (it is harmless even if you aren't), then update-exim4.conf, and finally invoke-rc.d exim4 reload. Then instead of using your smarthost, mail will be saved in BSMTP files in the specified directory.

Packaging and sending the mails onwards.

Now that the mails are being stored in this directory, they need to be sent onwards. Here is the script I used to do this; it needs to be run as root or as the Debian-exim user. It also either needs to be run interactively or within an ssh-agent.

#! /bin/bash -e


if [ $(ls /var/spool/exim4/bsmtp | wc -l) -eq 0 ]; then exit 0; fi
cd /var/spool/exim4/bsmtp
tar zcf $BSMTP_TGZ *

LOGFILE=`mktemp -t remotemail.log.XXXXXX` || exit 1

scp $BSMTP_TGZ $REMOTEHOST:bsmtp.tar.gz
ssh $REMOTEHOST sendmail-bsmtp | tee "$LOGFILE"

# remove the sent messages
for i in `sed -e 's/^Sent message //' "$LOGFILE"`; do
  if expr "$i" : "[A-Za-z0-9_-]\+$" > /dev/null; then rm -f "$i"; fi


exit 0

Then on the remote host, there is a small script called sendmail-bsmtp which runs the reverse. This assumes that the remote host is also running exim; this will need modification as appropriate. A directory ~/bsmtp is set up there.

#! /bin/bash -e

# This is intended to run on REMOTEHOST

cd ~/bsmtp
tar zxf ../bsmtp.tar.gz
rm -f ../bsmtp.tar.gz
for i in *; do
  /usr/sbin/exim4 -bS < $i
  echo "Sent message $i"
  rm -f "$i"
exit 0

And that's all.

Return to my homepage.