How to Tunnel SMTP (Postfix) server to Google (Gmail/Google Apps)

In /etc/postfix/main.cf:

# http://www.postfix.org/SASL_README.html#client_sasl_enable
#####################################################################
relayhost= [smtp.gmail.com]:587
smtp_connection_cache_destinations= [smtp.gmail.com]:587
smtp_use_tls = yes
smtp_tls_security_level=encrypt
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/gmail
smtp_sasl_security_options = noanonymous
smtp_sender_dependent_authentication = yes
sender_dependent_relayhost_maps = hash:/etc/postfix/sender_relay
smtp_generic_maps = hash:/etc/postfix/generic
#smtp_tls_cert_file = /etc/ssl/certs/smtpd.crt
#smtp_tls_key_file = /etc/ssl/private/smtpd.key
# cat /etc/ssl/certs/Equifax_Secure_CA.pem >> /etc/postfix/cacert.pem
smtp_tls_CAfile = /etc/postfix/cacert.pem
soft_bounce = yes
default_destination_concurrency_limit = 1
#####################################################################
In the same file – /etc/postfix/main.cf, please comment out:

 

# TLS parameters
#smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
#smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
#smtpd_use_tls=yes
#smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
#smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache

 

In /etc/postfix/gmail:
user1@postfix-server-custom-domain.com               user1@google-app-domain.com:user-password
# Login information for the default relayhost.
[smtp.gmail.com]:587               default-user@google-app-domain.com:default-password
In /etc/postfix/sender_relay:

user1@postfix-server-custom-domain.com  [smtp.gmail.com]:587

In /etc/postfix/generic:

www-data               noreply@google-app-domain.com

Now, the important notes, in /etc/postfix:

1.) postmap gmail
2.) postmap sender_relay
3.) postmap generic
4.) /etc/init.d/postfix restart (or ‘reload’ instead of ‘restart’ if you want to keep your server running)

Now, let me explain what this whole thing does:

From the config section, you are saying that the default relay host is “smtp.gmail.com”, on port 587, and the “[“, “]” specify that you do not want to do MX/DNS lookups every time. The next part says that you want to use TLS. This is something that google requires/enforces. I will temporarily skip down to the CA file. This is needed in order to verify Google’s CERT. Now, the next part (back up) is to look at the “gmail” map. Normally, if you wanted to default everyone’s email, this would be sufficient, with the section of the “default relay host”. This basically tells the server that anything and everything should be sent to Google (Gmail/Google App), and it lists the default user, domain, and password (where ‘google-app-domain’ is either your own custom domain under Google Apps, or Gmail). Now the extra step that I go through is the “sender_relay”. What that simply does is it acts like a “source” trigger. You list destinations for EACH email user. That simply says that if ‘user1@postfix-server-custom-domain.com’ sends an email, it should really go to the gmail server, and from there that trigger is matched up in the ‘gmail’ file for authentication. This allows you to have a “server” domain, which is actually hosted by Google (or NOT — you can host it ON the postfix server, in terms of where mail lives), and you can make it so that each user when sending email, actually sends as their own external IMAP account. One extra step that I’ve added is the “smtp_generic_maps”. The reason for this is to translate email that comes in from services like Apache (which generates from www-data@). This is not necessary, but it’s useful.

Why do this? If you have not figured out a good scenario for this, here is one:

You host a web-hosting service called ‘abc.com’. Every single user who signs up gets a ‘someusername@abc.com’. Your email is hosted on Gmail/Google Apps. Now the problem is that each user needs to be able to see their email locally (easy with imap — see my other article about mutt+msmtp) and the bigger problem is that each user needs to be able to send email “FROM” their own account, which again, is hosted on Gmail/Google Apps. Now let’s take it a step farther — each user has their own domain.tld, and they want to send email as themselves, when they send from the system. This is where the sender_relay file comes in. It just acts as an intercept filter/trigger, which looks for a certain username@abc.com, hooks it, and translates it into a mail server, and then hooks the user+pass for that email server. The end result is an extremely robust and powerful solution. The whole reason I started even looking at this is because I didn’t want to keep maintaining a full blown Zimbra server only for a 2-3 users, and it wasn’t reliable at home (even with some hacky distributed solutions), and it was not worth the cost to run it as a VM with Amazon. This brought me to Google Apps. The main problem was what I described above, and the second problem was having an “IP auth only”  SMTP server for dumb devices like the EMC Iomega Storage Brick, vCenter, and other things like that. The above solution solves all of these problems in an extremely elegant way.

Concerns?:

Yea — the user/password is stored in plain text. I really need to look for an encryption method. One solution I was thinking of was PGP/GPG-ing the plain text file, and then unlocking it only when I needed to make a change. This way I could decrypt, make a change, postmap it, and then re-encrypt the file. If anyone has a more elegant solution, please contact me. Hope this helped anyone looking for a good solution.

12 Thoughts on “How to Tunnel SMTP (Postfix) server to Google (Gmail/Google Apps)

  1. As far as protecting your credentials, while not encryption, this step makes it more secure:

    As noted, the /etc/postfix/sasl_passwd and the /etc/postfix/sasl_passwd.db files will contain SMTP credentials in plain text. You can change their permissions so that only the root user can read or write to the file. Run the following commands to change the ownership to root and update the permissions for the two files:

    sudo chown root:root /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db
    sudo chmod 0600 /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db

  2. Postfix - Gmail bridge on April 23, 2014 at 7:50 am said:

    Hi folks,
    I want to share my experience about my Postfix – Gmail bridge set-up.
    I was wanting to use Gmail for both incoming and outgoing emails and Postfix only for some kind of outgoing emails such as
    monitoring alerts, web application generated emails (password resetting links, account activation links, welcome messages, order details, information messages, spreading promotions, marketing emails etc…)
    And I honestly had no idea that how it can be done or even about the possibility.
    So, I asked Ventz (Petkov) for help, and he gave me very detailed informations.
    (Too many thanks to him for his help and valuable informations.)
    He routed me to correct way to figure out my set-up.
    So, I learnt what mean SPF, DKIM and how can I use them and I learnt more…

    Here is a similar reason why I do not want to bother myself and waste my time with Email Servers.
    http://blog.vpetkov.net/2010/11/15/how-to-tunnel-smtp-postfix-server-to-google-gmailgoogle-apps/

    As this set-up has some pros and cons, I have decided to eliminate some cons which were really important for my web application.
    As Gmail has daily email limitations, I had to move all email sending operations of web application generated emails to Postfix.
    So, I can avoid that limitation when the website has high traffic.
    And by doing this, it also avoids the network latency and connection fails between the Gmail and VPS, also avoids wasting of hardware resources.
    You can even close some services(ie: inet) and TCP/IP ports (25) for incoming traffic of Postfix (and/or directly from your Firewall).
    So, you convert it from lose-lose to win-win.

    Steps:
    – Set Postfix as null client but fill empty “relayhost =”
    – activate DKIM (ie: OpenDKIM) milter (mail filter) in Postfix.
    – Add following DNS Records (default._domainkey by Postfix, google._domainkey by Gmail) assuming you already have a PTR record for your FQDN host.domain.tdl

    TXT
    @ -> “v=spf1 ip4:[IP-Address] a mx include:_spf.google.com ~all”

    MX
    ASPMX.L.GOOGLE.COM. -> 1

    MX
    ALT1.ASPMX.L.GOOGLE.COM. -> 5

    MX
    ALT2.ASPMX.L.GOOGLE.COM. -> 5

    MX
    ASPMX2.GOOGLEMAIL.COM. -> 10

    MX
    ASPMX3.GOOGLEMAIL.COM. -> 10

    TXT
    default._domainkey -> “v=DKIM1; k=rsa; p=[key]”

    TXT
    google._domainkey -> “v=DKIM1; k=rsa; p=[key]”

    – Important 1: example@domain.tld should be created in Gmail accounts before sending emails from example@domain.tld via web-server.
    For an example; create no-reply@yourdomain.ext user first in Gmail accounts and then use it in web application.
    This seems unnecessary but trust me it is not.

    – Important 2: Go to Google Apps and add the IP address of the web-server.
    Google Apps -> Settings for Gmail -> Advanced settings -> Spam -> Email whitelist -> [IP-Address]

    – Important 3: Check the IP address of your web-server for blacklists. Change [IP-Address]: http://mxtoolbox.com/SuperTool.aspx?action=blacklist%3a%5BIP-Address%5D&run=toolpage

    – Important 4: Learn how to NOT write an email that seems like a spam. For tests: http://www.mail-tester.com/

    If all goes as well, your emails (both Gmail and Postfix) should land into inbox folder and not spam or junk folders.
    That’s all folks 🙂

    I hope this information can help to users who want to use Postfix – Gmail bridge as this way.

  3. James Austin on November 5, 2013 at 2:13 pm said:

    Thanks!

  4. Just wanted to let you know that this worked perfect. I’m using Ubuntu Server 12.04.1 LTS.

  5. thanks for the great article. you really helped me with setting up postfix for Google Apps

  6. Diederik on April 20, 2012 at 4:53 am said:

    hi Ventz,

    I still have an issue. mail I send from a vhost to that same host, doesn’t work as expected…
    I’ve been messing with the settings but I can’t seem to find the bug…

    To be clear: I run a mail() php script on mydomain.com when I send the mail to you@yourdomain.com everything works but when I send it to me@mydomain.com it doesn’t.

    depending on changes I make in the main.cf file it remains in the postfix queue forever (pointing to user@server-host) or I immediately get a bounce from google saying delivery to user@server-host failed permanently…

    I’m not sure what to do…

    regards,
    Diederik

    • Ventz on April 20, 2012 at 8:55 am said:

      I am going to email you some sample configs that you should be able to more or less drop in (read through them as I’ve commented in some stuff for the config values). Reply to the email and send me a copy of your configs if you still can’t get it to work after you try mine. Also, just for testing up front, use the ‘mail’ unix command to send, and trace the logs at the same time in another terminal — just to eliminate as many other variables as possible.

  7. Diederik on April 18, 2012 at 4:12 pm said:

    hi Ventz,

    thanks for your reply !
    #1 I think I found the issue for #1, one of the passwords was incorrect, causing the system to always fall back to the default user… my bad – too much late nite coding… I did make some additional changes, below is what I added (would love to hear your opinion about)

    // make it a null client ?
    mydestination =
    // needed to set this one for virtualmin (or it wouldn’t run)
    virtual_alias_maps = hash:/etc/postfix/virtual
    // not sure about these…
    inet_interfaces = loopback-only
    local_transport = error:local delivery is disabled

    // below goes your script…

    #2 What i did was adding a line in each vhost’s apache conf:
    php_admin_value sendmail_path “/usr/sbin/sendmail -t -i -f user@tld.com

    Did #2 still make my system vulnerable to processing s_p_a_m?
    google app smtp and mx records seem to work now…
    I didn’t quite understand the meaning of the generic file, I do now, but I still don’t see why I should implement it, in my case:
    apache noreply@tld.com

    Thanks for the tutorial, really helped me…

    PS: If you’d have time to review my setup I could give you access to my server. feel free to contact me.
    PPS: as you already guessed I’m running CentOS -> apache

    Regards,
    Diederik

    • Ventz on April 18, 2012 at 7:24 pm said:

      #2 would only make it vulnerable if you open port 25 from the outside, which you have no reason to open since everything is internal. That said, whatever PHP script you are using might make it vulnerable, depending if it’s accessible directly — don’t do this 🙂

      The generic file is a send re-write. It’s meant to rewrite non-routable/internal domains and subdomains. Example: Let’s say that you are on non-routable-node.domain.tld, and you send email from ‘user1’, you can originate the final hop before it hits outside your network as ‘user1@domain.tld’. You can use this to re-write stupid from addressees, like ‘apache@’ to something like ‘no-reply@’ so they make more sense, OR in case users need to respond to like ‘youraccount@’.

      Glad this is helping. I would rather not have access to your server :), but feel free to send me configs if you want and I’ll look at them. It sounds like you have everything working correctly though.

  8. Diederik on April 16, 2012 at 6:42 pm said:

    hi Ventz,

    I’m so glad I found your post, I’ve been struggling with this subject for a couple of well … nights – 😉
    Yet, it seems I can’t make it work 100% as intended. I can send emails from different users (hosts) and from php. But they always seem to originate from one user…

    also when sending from php, the name that shows up is apache (though the email is the default one)

    I’m gonna do some more testing soon, and hopefully post back here…

    I do feel your article put me on the right track…

    thanks
    D

    • Ventz on April 18, 2012 at 1:07 pm said:

      There are two separate issues here:

      1.) For the first problem “same user”, what unix user are you sending email from? It would always come from the unix user you are logged in from at the end of the day via a relay. In terms of email from different users/hosts, this is very easy (it’s actually what I am currently using). Let’s say you have your email server “192.168.1.25” and then some host “192.168.1.10”. On the host, you need to have a very minimalistic relay setup. In postfix, this would be the equivalent of a default ubuntu install, with a “relayhost = 192.168.1.25”. Set your hostname/origin, and your destination which should be set to “localhost.domain.tld, localhost” — so that you are not a final destination for your domain. Many people here make the mistake of adding their full TLD, which would make your email get stored locally. Now, on the email server, if you followed the tutorial, depending on who sends an email, it will route to the correct account. Again though, it would depend on the user.

      2.) This follows nicely into your second problem: same user from web/php. The issue with this is that everything will come from the user Apache is running under. On ubuntu, this is “www-data” by default. In centos and such, it’s “apache”. I know that this is very frustrating. The only solution I’ve found (which is mediocre) is to put in your main.cf “smtp_generic_maps = hash:/etc/postfix/generic” and then inside that “generic” file, having something like “www-data no-reply@somedomain.tld” or “apache no-reply@somedomain.tld” in your case. This will at least change the from on the fly when the email comes in.

      I am looking for a better solution to #2, so I would be very curious if there is something out there. I feel like there has to be a better solution, but I haven’t been able to find one.

Leave a Reply

Your email address will not be published. Required fields are marked *

>> NOTE: Please use <code>...</code> to post code/configs in your comment.