Exim hidden service FAQ

What should I do?

have [x]inetd start tor-smtp for connections on some port, and configure your mail server to try an SMTP session with the local host on that port for any .onion (and if you want to allow torque, any .tor) addresses; also configure x[inetd] (this is essential!) to pass your own .onion/.tor name as the first parameter to the tor-smtp program, and optionally the tor server's hostname/port as second/third parameters.

What exactly does the tor-smtp program do?

upon getting a connection it response with a 220 status code. It then reads the EHLO/HELO line and parses out the remote and local domains which may be a .onion/.tor addresses (first is the local, second remote on the EHLO/HELO). It then proceeds to connect to the remote mail server via tor. If the mail server's initial hello statement is negative (not code 220) then it returns a 421 code and closes the connection, otherwise it sends a EHLO/HELO with the local .onion address to the remote server. At this point we connect stdio with the connection to the remote server so that the response to the local HELO will be the response from the remote server, meaning that we have initiated a full SMTP connection now, and can proceed as the server wants.

How do I configure my mail server?


make sure your exim knows that your-local-domain.onion is in the local_domains list (debian package has that list only I think), otherwise you get a mail loop!

For exim, add these two routers:

  # tor stuff first
  # if we're submitting mail *from* a .tor/.onion address,
  # make sure any header lines that may give us away is
  # stripped out, and add a new, cryptic Message-ID.
  # In address_data we store the name we should HELO as.
          debug_print     = "R: manualroute from .onion to $local_part@$domain"
          driver          = manualroute
          domains         = ! +local_domains
          condition       = ${if match {$sender_address_domain}{\N.*\.(onion|tor)$\N}}
          address_data    = $sender_address_domain
          transport       = remote_smtp_onion
          self            = send
          route_list      = * localhost
          headers_remove  = Received:Message-ID:X-Mailer:User-Agent
          headers_add     = Message-ID: <${lc:${sha1:$message_id}}@$sender_address_domain>

  # this catches the case where we're submitting mail
  # from a regular email address where we don't need to
  # rewrite any headers
          debug_print     = "R: manualroute for $local_part@$domain"
          driver          = manualroute
          domains         = ! +local_domains
          transport       = remote_smtp_onion
          self            = send
          route_list      = *.onion localhost ; *.tor localhost
          address_data    = $smtp_active_hostname

this uses a transport that is configured as such:
        debug_print = "T: remote_smtp_onion for $local_part@$original_domain"
        driver = smtp

        # set helo_data to where we want to connect to,
        # for the proxy program tor-smtp
        helo_data = "$address_data $original_domain"

        # wherever we configured our script at
        port = 1000

        # cannot use TLS otherwise it will EHLO again!!
        hosts_avoid_tls = *

Now you explained exim, but not [insert my favourite mail server]!

Well, feel free to use any mail server. For outgoing .onion/.tor mail, you must configure it to connect to the local host on port 1000 (or any other port you chose) and give the .onion/.tor domain the smtp proxy should connect to in it's HELO or EHLO (after the greeting). We hope that most mail servers can be configured to use a custom EHLO or HELO greeting.

How do I configure xinetd?

service tor-smtp
        socket_type     = stream
        protocol        = tcp
        port            = 1000
        bind            =
        type            = UNLISTED
        wait            = no
        user            = debian-tor
        server          = /where/is/tor-smtp
        server_args     = localhost 9050

I need to use a different tor server

Add the tor server and port to the server_args in the xinetd configuration, as first two parameters, see above example.

How do I configure inetd?

We don't know.

Can I run the tor-smtp program without xinetd/inetd?

Yes, you can. Here's an init script for it that requires socat for listening instead:

# tor-smtp Server

# Provides:          tor-smtp
# Required-Start:    $local_fs, $remote_fs, $network, $named, $time
# Required-Stop:     $local_fs, $remote_fs, $network, $named, $time
# Should-Start:      $syslog
# Should-Stop:       $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Starts the tor-smtp proxy
# Description:       Start the tor-smtp proxy,
#                    a proxy to allow properly configured MTAs
#                    to connect into onionspace

set -e


test -x $DAEMON || exit 0

case "$1" in
    echo -n "Starting tor-smtp server: $NAME"
    start-stop-daemon --start --background -m --pidfile /var/run/tor-smtp.pid --user $OWNER --exec $DAEMON
    echo "."
    echo -n "Stopping tor-smtp server: $NAME"
    PID="`ps -auxw 2> /dev/null | grep 'TCP4-LISTEN:1000' | grep -v grep | awk '{print $2}'`"
    if [ "$PID" ]
      kill $PID 2> /dev/null
    rm -f /var/run/tor-smtp.pid
    echo "."
    echo -n "Restarting tor-smtp server: $NAME"
    $0 stop
    sleep 1
    $0 start
    echo "."
    echo "Usage: /etc/init.d/$NAME {start|stop|restart}"
    exit 1

exit 0

while tor-smtp-wrapper.sh contains the following

exec /usr/bin/socat TCP4-LISTEN:1000,fork,bind= \

Note that I haven't tested this, so if you do and it doesn't work let me know.

Why should I use this?

See the whitepaper.