Sendmail: Smart Host Authentication by Sender

Sendmail is one of those applications that can do just about anything (as long as you know the secret handshake that gets you access to detailed information about it’s configuration).

I’ve been using it for about 1 year to allow my company’s website to send email to our users.  To avoid all the headaches involved in making sure our emails don’t get rejected as spam, we use googlemail as a smart host since they host our email accounts for our domain.

This has been working great, but recently we ran into a limitation that would be a deal breaker if it couldn’t be solved.

The Problem:

  1. When using googlemail as your smart host, you must use authentication and Google rewrites the from address of all your emails to the user’s email address that you use to authenticate.  Thus, if you authenticate with webmaster@example.com’s credentials, all email from your server will seem to come from webmaster@example.com.  Even if you specify a different sender!
  2. When sendmail is configured to use a smart host that requires authentication (like googlemail), it chooses the authentication credentials based on the host name or IP address of the smart host.  So, unless you use multiple smart hosts, sendmail will only use 1 set of authentication credentials when connecting to the smart host.
  3. We are now hosting 2 websites on the same server with completely different domain names that each need to send email from different addresses that belong to their respective domains.

When you combine all three parts, the problem becomes clear:

How do I send email from info@yyy.com when sendmail will always use info@zzz.com’s credentials for smart host authentication, thus making Google rewrite the from address so that all email from my server appears to come from info@zzz.com?

The Solution:

To me, the best solution would be for sendmail to choose smart host authentication credentials based on the sender address of each email.

For example:

  1. Sendmail receives an email message to deliver from info@yyy.com
  2. Instead of looking up “smtp.googlemail.com” in authinfo, it looks up “info@yyy.com”

Seems simple enough, but, after hours of searching the web, I found that sendmail is just plain not configured to do this.

However, everything it needs to be able to do this is already available, it just doesn’t use it.  So I decided to make sendmail use it by editing the sendmail.cf file.

I know, I know, I’m supposed to use sendmail.mc, but darn it all if I wasn’t able to get this to work using the macro file.

So, without further ado, here’s what I did to make sendmail behave the way I wanted it to.

The How To:

Assumptions:

I’m assuming that you already have sendmail configured to use a smart host that requires authentication.  It is beyond the scope of this document to cover that.

Instructions:

1) Edit the authinfo section of sendmail.cf so that it looks like this:

######################################
### authinfo: lookup authinfo in the access map
###
###     Parameters:
###             $0: {f}
###             $1: {server_name}
###             $2: {server_addr}
######################################
Sauthinfo
R$*        $: <$(authinfo AuthInfo:$&{f} $: ? $)>
R<?>      $: <$(authinfo AuthInfo:$&{server_name} $: ? $)>
R<?>      $: <$(authinfo AuthInfo:$&{server_addr} $: ? $)>
R<?>      $: <$(authinfo AuthInfo: $: ? $)>
R<?>      $@ no                      no authinfo available
R<$*>    $# $1

The key here is the $&{f} macro.  In sendmail, it stands for the sender’s address from the envelope of the email.

The above code tells sendmail to look for entries in the authinfo file that match the sender’s email address.  If no match is found, then check for entries that match the smart host’s name/IP.

In effect, this preserves sendmail’s original behavior as the fall back if no match is found in the authinfo file for the sender’s address.

2) Add sender credentials to the authinfo file (its location is defined by the authinfo feature in sendmail.mc):

AuthInfo:info@ex.com “U:info@ex.com” “P:xx” “M:PLAIN”
AuthInfo:info@yyy.com “U:info@yyy.com” “P:xx” “M:PLAIN”
AuthInfo:info@zzz.com “U:info@zzz.com” “P:xx” “M:PLAIN”

AuthInfo:smtp.sh.com “U:info@ex.com” “P:xx” “M:PLAIN”
AuthInfo: “U:info@ex.com” “P:xx” “M:PLAIN”

In the example above, the first 3 entries are credentials for different senders that use the server to send email (they take advantage of the changes we made in step 1).  The last 2 entries are the original smart host authentication configuration which ensures that sendmail will still be able to connect to the smart host and send the email using a default set of credentials, even if the sender’s address does not match any of the other entries.

3) Remake the authinfo database using the “makemap” command.

4) Make sure to comment out any lines in your init script for sendmail that recompile sendmail.cf using the sendmail.mc script.  The location of this file on Redhat variants is: /etc/init.d/sendmail

(if you don’t do this, your changes to sendmail.cf will be lost when you restart sendmail!)

5) Restart sendmail.

You should now be able to control which user’s credentials are used to authenticate with the smart host on a case by case basis by changing the sender’s address on the email.

This is specified using the -f flag when calling sendmail on the command line (like PHP’s mail() function does).

Final Thoughts:

While this gets the job done, it would be nice to be able to incorporate the changes in step 1 into the sendmail.mc file.  This would make it much easier to maintain since anyone who runs the “make” command on the /etc/mail directory will destroy the changes we made to sendmail.cf in step 1.

About cthayer

- Vice President - Technology Enthusiast - Soccer Nut

Posted on October 3, 2008, in Sendmail and tagged , . Bookmark the permalink. 19 Comments.

  1. You need to edit /usr/share/sendmail-cf/m4/proto.m4, if you want your changes to be preserved when you run “m4 sendmail.mc”. Just search the file for “AuthInfo” and you will find the right section quickly.

    On a final note: thank you a thousand times! This blog was exactly what I was looking for! You saved my skin!

  2. This is much easier done by using the smarttable file to configue what sender addresses should be handled by which smarthosts.

    http://web.archive.org/web/20071021005904/http://anfi.homeunix.net/sendmail/smarttab.html

    Usage

    In smarttable file you can put entries like the ones given below:

    test@mike.com.hk lesspopular.mailhub.com
    @mike.com.hk popular.mailhub.com
    test@domain.pl uucp:nodex
    test@domain.us esmtp:[smtp.domain.us]:my.isp
    # relay for sender [version 8.2+ of smarttable]
    @ relay:smtp.myisp.com

    lesspopular.mailhub.com will be used to relay messages send from test@mike.com.hk. Messages from remaining addresses in mike.com.hk will be relayed via popular.mailhub.com. You can also specify mailer used as shown in the remaning lines.

    The lastest smarttable version is 8.5 released 2002-07-28. I detected problems in versions 8.1-8.4
    Install

    1.

    Create /etc/mail/smarttable file and compile it using makemap.
    2.

    Copy provided smarttable.m4 file into cf/feature directory.
    Use “Save as” command in your browser. In some cases “copy and paste” looses required info (e.g. tabs – \t)
    3.

    In *.mc file you use to generate sendmail.cf add:

    FEATURE(`smarttable’)dnl

    and generate new sendmail.cf or sendmail-test.cf.

    Tests

    You can use commands given below for testing the feature:

    sendmail -C sendmail-test.cf -bt <<END
    3,0 recipient@test.com
    .Dfsender@sender.domain
    3,0 recipient@test.com
    END

    Additional

    * smarttable uses sender addresses befere masquerading (e.g. genericstable rewrite).
    * smarttable is not consulted for deliveries to addresses in local domains
    * mailertable is consulted before smarttable
    * DO NOT use feature/smarttable.m4 pre 8.5 releases
    o versions 8.2-8.3 were newaliases unfriendly
    o versions 8.1-8.4 routed local address with no domain part via smarttable
    * Another solution for sender based smart host selection has been proposed by Neil Ricket. HACK(`sender_based_routing') is available at http://www.cs.niu.edu/~rickert/cf/
    * Example of smarttable usage is given at http://lena.franken.de/linux/mail_sendmail_etc.html#sendmail_from_based_routing

    Original Posting

    googleThe posting
    Subject: Re: How to relay the mail according to the sender domain
    Date: 1999-02-05
    Newsgroups: comp.mail.sendmail
    Message-ID:

    • @geohump: Thanks for the tip on smarttable. That looks like a very useful addition to sendmail.

      However, it does not solve the problem I was writing about in the article. My issue was that we only had one smart host and needed to authenticate with different email addresses. Not route outgoing emails to different smart hosts.

  3. Thanks cthayer
    This blog was exactly what I was looking for. It solved my problem.

  4. Hello,
    We are using google apps business edition. I have configured sendmail to relay emails of our google apps account but what I want to configure is, if user john having email address “john@domain.com” sends email to any user, it should get saved in the sent folder of the mailbox of the user john at google apps and so on for other users also. Is it possible to achieve this?

    • @Dhanil: If you authenticate with Google as user “john” to do the relay, then Google should save the message in the user’s sent history. This post is all about how to authenticate with Google as different users based on the sending email address. Also, check out the comment above by quirks.

      • Hi all

        …and if i want to auth in exchange 2007 only from @external mails….

        i mean: i have a smart_host in my domain (exchange 2007), but not permit relays to @external, so, i want to auth only when the rcpt is @external.

        i can do it via authinfo file + “-f” parameter in sendmail command, but i need to set the config static in order to work with any application that use sendmail to send @external mails.

        for example: i have a standard java program(i can’t add or change code) that sends mails, and accept a smtp server as a parameter.

        how can i do that?

        regards

  5. Nice work!will recommend to all!

  6. Santiago Burgues

    dude, this is what i’ve been trying to do for the last 6 months!

    I got it working by using sendmail -f but when sending emails from my iPhone it just falls back to the ‘default’ auth string, like if it is not recognizing the FROM field or it does not match.

    Any ideas? How can I ‘debug’ this?

    I’m trying to set this up using z-push.

    Kind regards,

    Santiago

    • Santiago Burgues

      (im replying on my own comment cause i forgot to check the ‘notify’ option)

    • Glad this post was helpful.

      It can be really hard to debug this stuff and I don’t know how z-push works in enough detail to be very helpful. If you have some way to view the email just before it reaches sendmail that could give you some insight into what’s going on. Also, you can view the source of the email after it’s been delivered to see headers and other information about it. If you’re using webmail look for an option to view the source or view the original (don’t use the right click menu).

      If I was to take a wild guess, I would suspect that the from address on the envelope of the email is not what you expect it to be and doesn’t match anything in your authinfo file so it uses the default auth credentials.

      One thing to remember is that the from address on the envelope is not necessarily the same as the one in the “From” header on the email message. In fact, it is often different in sophisticated email systems.

      • Santiago Burgues

        Hey!

        Thanks for taking time to read my comment and replying 🙂

        By the time you responded I had already uninstalled sendmail and configured Postfix lol

        But guess what, the problem was still there, the same. That helped me realize that the problem was not the MTA but the app I was installing.

        So I found it’s logging flag, turned it on and immediatly noticed what u said, the envelope sender wasn’t even being set.

        So I digged into the code of z-push and forced it to set the envelope sender by using the 5th argument in php’s mail() function, that argument ‘forwards’ to sendmail so what I did to pass ‘-f $sender’ in that argument and voilá!

        I got push mail from GMail using IMAP + Z-Push (open source implementation of Exchange’s ActiveSync) and an SMTP relay with sender dependant authentication working 🙂

        Now all it’s left is to figure out how to automate the whole authentication thing.
        The problem with this is that I have to manually ‘register’ each user in the passwords map and not just that, they have to give me their plain password!…

        So, what I was thinking was to investigate if I could somehow catch the user’s password that was used to authenticate to IMAP and auto add those credentials to the pswds map, then regenerate the db and somehow encrypt it.

        I would always be using GMail’s SMTP server since I want this for our company’s google apps account and our personal GMail accounts.

        What do you think? Is this a crazy thought? 😛

        Kind regards,

        Santiago

  7. helpful article,
    at the opposite of a lot of web pages with nothing really interesting about sendmail configuration. It helps a lot.
    congratulations

  8. полная ………………….

  1. Pingback: Configuring Sendmail to relay through Gmail SMTP « The AppGirl Blog

  2. Pingback: TecnoFrams » Blog Archive » Configurando Send Mail usando Gmail como Relay SMTP (centos 5.2)

  3. Pingback: Setup sendmail (notifications) for GMAIL SMTP « darryn van tonder

  4. Pingback: CONFIGURING SENDMAIL TO RELAY THROUGH GMAIL SMTP | IT-News

Leave a reply to cthayer Cancel reply