Tag Archives: email

When your on-the-road ISP blocks your outbound mail

Now, we talked about allowing your computer to relay mail through the home machine when the ISP through which you’re connecting has made it onto a block list. What do you do when the ISP simply blocks all outgoing connections on port 25? Now you can’t even connect to your home computer to relay the mail.

The ISP does this to force you to pass email through their servers. The hope is that infected Windows computers will just try to open connections directly, and not forward the mail through the ISP servers. As noted in this story, that is not necessarily true.

So, now you find yourself unable to open connections on port 25, but you still want to send email. You could set up your computer to relay mail through the ISP’s servers, as described in this earlier article, but that may not be convenient if, for instance, you’re accessing the Internet at a relative’s home, since they would have to give you their passwords for you to do that.

So, the first thing to do is to check that you can connect to your home computer on the ESMTP port number 587. Telnet onto that port number on your home computer, and if you get a response, then this technique will work for you.

First of all, you should already have set up relaying as described here. If you set it up a while ago, verify that your keys are still valid and haven’t expired.

As we’re discussing this in the spirit of a temporary work-around, we’ll be editing the sendmail.cf file directly. First, of course, make a backup copy of your current sendmail.cf file, because you’ll want to reset it to its former behaviour after you stop using this particular ISP.

Now, go into your sendmail.cf file and find the smart relay line. It will look something like this:

# "Smart" relay host (may be null)
DS

Change that line to indicate that you’re sending ESMTP to your home machine. It will look a bit like this:

# "Smart" relay host (may be null)
DSesmtp:mail-host.example.com

Next, we have to tell sendmail that it is to use port 587 for outbound mail to esmtp smart relays. Locate the block in the sendmail.cf file that looks like this:

Mesmtp,         P=[IPC], F=mDFMuXa, S=EnvFromSMTP/HdrFromSMTP, R=EnvToSMTP, E=\r\n, L=990,
                T=DNS/RFC822/SMTP,
                A=TCP $h

and change the last line to read:

                A=TCP $h 587

That’s it. Restart the sendmail program, and you should be able to relay all mail through your home machine using authenticated relaying on port 587.

When other sites discard or refuse your email

We’ve covered setting up your sendmail to act as a relay for certain computers. Now, we look at another relaying problem.

You like running your own sendmail, you’re using it to manage your own email accounts. You could use your ISP’s mail server for all outbound messages, but let’s say you’re not doing that. Now, some third party, maybe another ISP, let’s call them “Dogers”, decides to silently discard all email coming from IP blocks owned by your ISP unless the sending IP number is one of the mail servers of your ISP. Even if you’re running a responsible sendmail on a static IP number, messages sent to “Dogers” just vanish.

The solution is to arrange your sendmail so that, when sending to certain domains, it relays the messages through your ISP’s servers. We’ll need two more features for this. First, the mailertable function will allow you to use a different mailer for certain addresses. Second, depending on your ISP, you may have to authenticate yourself with the ISP’s server before it will relay your messages. This configuration will show how to perform that authentication.

Make sure your sendmail.mc contains the following two lines before the first “MAILER” line:

FEATURE(`authinfo',`hash /etc/mail/auth/client-info')dnl
FEATURE(`mailertable')

Also, add the following line anywhere in the file:

define(`confAUTH_MECHANISMS', `EXTERNAL GSSAPI DIGEST-MD5 CRAM-MD5 LOGIN PLAIN')dnl

You will need to have cyrus-sasl installed, and configured for logins. Here is a sample cyrus-sasl configuration invocation:

./configure --prefix=/usr/local --enable-anon --enable-plain \
       --enable-login --disable-krb4 --with-mysql \
       --with-saslauthd=/var/state/saslauthd --with-openssl=/usr/local/ssl \
       --with-plugindir=/usr/local/lib/sasl2/ --enable-cram \
       --enable-digest --enable-otp --without-des

OK, now the mailertable entry. Add a line for the dogers domain, telling your sendmail to forward mail for those addresses through your ISP’s server:

dogers.com      smtp:smtp..

Now, to authenticate with the ISP. We told sendmail that our credentials would be stored in /etc/mail/auth/client-info, so we create a file there:

AuthInfo:smtp.. "U:root" "I:wintertoad@." "P:" "M:LOGIN"

Then, we just have to rehash the mailertable and authentication files with a command like this:

# makemap hash file.db < file

Now, assuming you’ve rebuilt your sendmail.cf after the changes we made to the .mc file above, you can just send a SIGHUP to the sendmail processes, and you should be able to send email to anybody at the dogers.com domain by relaying those messages through your ISP’s mail server.

Why don’t I get spam?

I have an anti-spam trick. It won’t work for most people, but there might be some people out there who are inclined to take advantage of it. For the rest, this might be educational.

The trick that I use depends on the fact that I have my own domain. That means I can run sendmail on my computer, and I can create email addresses quickly and easily. I will use the domains example.com, example.net, and example.org for this document, as recommended in RFC 2606.

The basic idea is this: instead of having one email address, I have dozens. I create a new email address for every person with whom I exchange messages, as well as addresses for websites and companies when necessary. If an email address is accidentally revealed, or if one of the companies decides to start sending annoying amounts of unsolicited mail, I simply expire the email address and, if desired, contact the sending party to tell them about the new address. I don’t have to contact all of my friends whenever I turn off one address, only the one person who uses that address to talk to me.

OK, how is this implemented? There are two things I have to do. First, I need my sendmail to accept the messages for the active addresses, and send them all to me. Second, I have to ensure that my outbound email has the correct Reply-To: address for the particular recipient of the message.

If you’re familiar with sendmail, you can probably guess how I do the first thing. I set up a virtual user table. Here’s the sendmail.mc file used to make this work:

divert(0)dnl
VERSIONID(`sendmail.mc for example.com version 01')
OSTYPE(linux)dnl
DOMAIN(example.com)dnl
FEATURE(`nouucp', `reject')
FEATURE(`virtusertable', `hash /etc/sendmail/virtusertable')dnl
FEATURE(`genericstable', `hash /etc/sendmail/genericstable')dnl
FEATURE(`local_procmail', `/usr/local/bin/procmail')
FEATURE(`access_db', `hash -T /etc/mail/access')
FEATURE(`mailertable')
GENERICS_DOMAIN(mailhost.example.com)
MAILER(local)
MAILER(smtp)
define(`CERT_DIR', `MAIL_SETTINGS_DIR`'certs')dnl
define(`confCACERT_PATH', `CERT_DIR')dnl
define(`confCACERT', `CERT_DIR/CAcert.pem')dnl
define(`confSERVER_CERT', `CERT_DIR/MYcert.pem')dnl
define(`confSERVER_KEY', `CERT_DIR/MYkey.pem')dnl
define(`confCLIENT_CERT', `CERT_DIR/MYcert.pem')dnl
define(`confCLIENT_KEY', `CERT_DIR/MYkey.pem')dnl
Cw mailhost.example.com
Cw example.com

Then, I create a file called /etc/mail/virtusertable.src. It contains entries similar to this:

hotels@example.com                      error:nouser Spammers found this address

disposable0000@example.com myself

ebay@example.com myself
electronics@example.com myself
slashdot@example.com myself
thinkgeek@example.com myself

mail-default-0000-r2@example.com myself
mail-0000-r7@example.com myself
mail-0001-q3@example.com myself
mail-0002-a4@example.com myself
mail-0003-c8@example.com error:nouser Spammers found this address
mail-0004-d7@example.com myself

The addresses I create for regular correspondance are just successive numbers, plus an unpredictable sequence of two characters to avoid dictionary attacks.

Now, recall that sendmail doesn’t read the virtusertable.src file, it reads another file called virtusertable.db. I’ve got a little Makefile in /etc/mail that I use to keep things up to date:

all : genericstable.db virtusertable.db mailertable.db aliases.db access.db

%.db : %.src
makemap hash $* < $<

aliases.db : aliases
newaliases

hup : all
killall -HUP sendmail

Now, I can change the virtusertable file, and when it looks correct, issue (as root) the command:

make -C /etc/mail hup

This will update the appropriate database file, and send a SIGHUP to sendmail, telling that program to reload its databases.

So, that’s the receiving side. How about sending? There may be a way to configure sendmail to rewrite the outbound addresses according to a database of recipients, but I haven’t figured one out. Instead, I have written a bit of code for my email client, which is rmail mode in Emacs. Here are the relevant bits of Emacs Lisp:

(setq user-mail-address "bounces0000@example.com")
(setq mail-specify-envelope-from t)

(setq outbound-address-alist
'(
("joe@example.org" "mail-0000-r7@example.com")
("frank@example.org" "mail-0001-q3@example.com")
("wilbur@example.net" "mail-0002-a4@example.com")
("euripedes@example.net" "mail-0004-d7@example.com")
(nil "mail-default-0000-r2@example.com")
)
)
(setq full-name "Winter Toad")

;; a function to parse out the header and send email as if from
;; different usernames. That way, I can obsolete a username if it
;; gets spam.
(add-hook 'mail-send-hook
'(lambda ()
(narrow-to-region 1 (mail-header-end))
(beginning-of-buffer)
(expand-mail-aliases 1 (mail-header-end))
(re-search-forward "^To: ")
;; parse out the recipient address
(let (recipient from-whom)
(cond
((looking-at "\\([^ \\t]*\\)$")
(setq recipient (match-string 1)))
((looking-at "[^<]*<\\([^>]*\\)>$")
(setq recipient (match-string 1))))
(setq from-whom (or (cadr (assoc recipient outbound-address-alist))
(cadr (assoc nil outbound-address-alist))))
(end-of-line)
(newline)
(insert "From: " full-name " <" from-whom ">")

(re-search-forward "^Reply-to: ")
(let ((namestart (point-marker)))
(end-of-line)
(kill-region namestart (point-marker))
(insert from-whom)))

(narrow-to-region 1 (1+ (buffer-size)))))


What this does is to insert a hook into the mail system when I hit send. A bit of elisp locates the email address in the “To:” field, and tries to match that string to one of the names in the ‘outbound-address-alist’. If it finds a match, it inserts the corresponding data into the “Reply-to:” field. If no match is found, or if there are multiple recipients, it uses the default fallback address.

It also sets the sender address to bounces0000@example.com, which means that automated replies, such as sendmail daemon warnings and errors, will be delivered to that address. It should be redirected in the virtusertable to some appropriate address so that you can be notified of problems at the recipient’s end (though many systems no longer generate bounce messages, because of spam abuse).

Anyway, with all this, I get really no spam. Every few months I may get one message on one of my email addresses, typically one that I used for a forum post or to send a bug report or patch to a mailing list. I retire the address, set up a new one, and never get spam at that address again.

Some time later I’ll describe the cryptographic certificates in the mail configuration, and how they allow secure relaying.