57

I'm trying to get email reports from our AWS EC2 instances. We're using Exchange Online (part of Microsoft Online Services). I've setup a user account specifically for SMTP relaying, and I've setup Postfix to meet all the requirements to relay messages through this server. However, Exchange Online's SMTP server will reject messages unless the From address exactly matches the authentication address (the error message is 550 5.7.1 Client does not have permissions to send as this sender).

With careful configuration, I can setup my services to send as this user. But I'm not a huge fan of being careful - I'd rather have postfix force the issue. Is there a way to do this?

John Whitlock
  • 1,037
  • 2
  • 9
  • 14

5 Answers5

83

This is how to really do it in postfix.

This config changes sender addresses from both local originated, and relayed SMTP mail traffic:

/etc/postfix/main.cf:

sender_canonical_classes = envelope_sender, header_sender
sender_canonical_maps =  regexp:/etc/postfix/sender_canonical_maps
smtp_header_checks = regexp:/etc/postfix/header_check

Rewrite envelope address from email originating from the server itself

/etc/postfix/sender_canonical_maps:

/.+/    newsender@address.com

Rewrite from address in SMTP relayed e-mail

/etc/postfix/header_check:

/From:.*/ REPLACE From: newsender@address.com

Thats very useful if you're for instance using a local relay smtp server which is used by all your multifunctionals and several applications.

If you use Office 365 SMTP server, any mail with a different sender address than the email from the authenticated user itself will simply be denied. The above config prevents this.

Jasper
  • 1,024
  • 9
  • 7
  • Thanks! This looks like what I was looking for. Unfortunately, my access to Office 365 was two jobs ago. Can someone confirm if this works for them? – John Whitlock Mar 27 '15 at 18:45
  • 1
    I can. I'm using this with office 365. – Jasper Mar 28 '15 at 19:15
  • 2
    When using `sender_canonical_maps` postfix cannot save rejected mail to local spool and instead tries to send it through relay infinitely – basin Sep 25 '15 at 19:58
  • 2
    @Jasper FYI I found this easier to change the above configlines `postconf -e sender_canonical_classes=envelope_sender,header_sender` `postconf -e sender_canonical_maps=regexp:/etc/postfix/sender_canonical_maps` `postconf -e smtp_header_checks=regexp:/etc/postfix/header_check` – Jacob Evans Oct 05 '15 at 12:56
  • had a similar problem, __sender_canonical_classes = envelope_sender__ saved my day! – Stephan Richter Feb 19 '18 at 17:39
  • I realize this is an old thread, but it really saved the day for me, so thanx! Also, is there a way to rewrite the "from" address that shows up when the message is viewed in a mail client tied in to that Office 365 account? I'm seeing mail from, e.g., root@mycroft.localdomain when I'd like it to be one of my server-side accounts. – Mark Olbert May 09 '19 at 03:57
  • I am using `/From:(.*)/ REPLACE From: "${1}" ` this will show the original FROM string as text in most mail programs. – masgo Aug 13 '19 at 22:24
  • It complains when I use `"${1}". `out-of-range replacement index ` – Adam Oct 09 '19 at 21:57
  • this got my postfix into an infinite bounce loop with gmail... – Janus Troelsen Apr 14 '20 at 22:27
  • It looks like you can skip the `smtp_header_checks` part if you set `local_header_rewrite_clients` accordingly, for instance : `local_header_rewrite_clients = permit_inet_interfaces permit_mynetworks` will apply `sender_canonical_maps` configuration to emails originating from the server itself _and_ from the clients in `$mynetworks`. – nathou Aug 01 '22 at 14:22
20

The optional generic table specifies an address mapping that applies when mail is delivered (sent) from server.

This is the opposite of canonical mapping, which applies when mail is received by server.

(Note: both FROM and TO addresses are matched for replacement for any of generic and canonical tables.)

Using canonical table when mail is received by server is already explained is other answers.

You can rewrite FROM addresses when mail is sent from server using smtp_generic_maps.

According to postfix documentation :

/etc/postfix/main.cf:
    smtp_generic_maps = hash:/etc/postfix/generic

/etc/postfix/generic:
    user@localdomain.local      account@isp.example.com
    @localdomain.local          wholedomain@isp.example.com

Then do:

sudo postmap /etc/postfix/generic
sudo /etc/init.d/postfix reload

References:

Jocelyn
  • 330
  • 2
  • 7
  • 1
    This works but how can I also change the FROM name ? – JoaMika Sep 12 '16 at 10:13
  • My experience with generic maps is that it will identify both FROM and TO addresses, use canonical maps to force just the FROM address as the OP asked for – doz87 Nov 24 '16 at 23:32
  • Is it possible to change sender's mail and match senders addresses using regex ? – W.M. Aug 25 '17 at 16:24
  • @doz87 both FROM and TO will be matched by both canonical and generic maps. I have updated my answer to explain the difference between the two maps. – Jocelyn Aug 26 '17 at 18:02
  • @W.M. yes, you can use regexp. I never tried it but you would probably have to change `hash:` to `regexp:` in main.cf and use lines like `/foo.*@localdomain.local/ account@example.com` in generic map. This is explained in the man page : http://www.postfix.org/generic.5.html – Jocelyn Aug 26 '17 at 18:13
  • This is it. It is much simpler than the most upvoted solution here. – Benjamin Hastings May 10 '22 at 14:33
  • This solution using generics was the one that worked for me and allowed me to change the "From"/sender address in outgoing emails. I don't think canonical maps, as suggested by other answers, are the right solution; I tried using canonical maps and it did not alter the sender address. – Aquarelle Jun 01 '22 at 19:14
8

Update: On the advice of an IT friend, I'm running postfix on all my servers, rather than making one cloud mail server. Here's my solution so far:

/etc/postfix/main.cf

# output of hostname -f - mail from local users appears to come from here
myhostname = domU-01-02-03-04-05-06.compute-1.internal
# Local delivery - include all 127.0.0.1 aliases from /etc/hosts
mydestination = $myhostname, $mydomain, rest_of_entries_from_hosts
# Needed for address translation to work
myorigin = $mydomain

# Talking to MS Online
# :submission = port 587
relayhost = [smtp.mail.microsoftonline.com]:submission
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options =   # Yes, leave empty
smtp_tls_security_level = encrypt
smtp_generic_maps = hash:/etc/postfix/generic

# Enable if you need debugging, but it does leak credentials to the log
#debug_peer_level = 2
#debug_peer_list = smtp.mail.microsoftonline.com

# Only listen on the local interfaces (not the public)
inet_interfaces = localhost

# I left out a bunch of CentOS defaults.  postconf -n is your friend.
# These are included
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases

/etc/postfix/sasl_passwd

# Run postmap /etc/postfix/sasl_passwd after editing
# Also, chown root:root; chmod 600
smtp.mail.microsoftonline.com relayer@hosteddomain.com:YourP@ssw0rd

/etc/postfix/generic

# Run postmap /etc/postfix/generic
# I've seen local mail come from either source
# output of dnsdomainname
@compute-1.internal relayer@hosteddomain.com
# output of hostname -f
@domU-01-02-03-04-05-06.compute-1.internal relayer@hosteddomain.com

/etc/aliases

# Run newaliases after changing
# Lot of stuff here. Mostly, just make sure the graph points to root, such as
mailer-daemon:  postmaster
postmaster:     root

# And the important part - your email or distribution group
root:           awsadmins@hosteddomain.com

/etc/passwd

# Sometimes it helps to expand the name, so email comes from 'root at aws host 5'
#  rather than just 'root'
# Was
#root:x:0:0:root:/root:/bin/bash
# Is
root:x:0:0:root on aws host 5:/root:/bin/bash

Things I'm happy about:

  • A lot of mail gets sent to root, and the one line in alias directs who gets it.
  • All mail from local users is translated to coming from relayer@hosteddomain.com, so it gets through the MS Online SMTP server.
  • postfix has much better documentation than sendmail.

Things I'm not happy about:

  • Custom changes are required for each host, and several steps. I wrote a bash script to help.
  • The passwd name trick doesn't always work, and it can be difficult to figure out what server a mail is coming from.
  • Every mail sent puts three warnings in the log:
    1. warning: smtp.mail.microsoftonline.com[65.55.171.153] offered null AUTH mechanism list (SMTP server sends a null AUTH list before STARTTLS, but AUTH LOGIN after).
    2. certificate verification failed for smtp.mail.microsoftonline.com: num=20:unable to get local issuer certificate (There are some config options around certs, but I'm not sure if mail delivery breaks when the cert is renewed)
    3. certificate verification failed for smtp.mail.microsoftonline.com: num=27:certificate not trusted (Same as #2)

Thanks to the serverfault community for sharing strong opinions on mail servers.

John Whitlock
  • 1,037
  • 2
  • 9
  • 14
5

You can use smtpd_sender_login_maps to specify a list of maps: sender address - user.

Example:

smtpd_sender_login_maps = 
    hash:/etc/postfix/login-map 

/etc/postfix/login-map:

mail1@domain    userlogin
mail2@domain    userlogin, otheruser@example.com

It does work for sending, it should work for relaying the same way.

silk
  • 918
  • 5
  • 13
  • Is the purpose to rewrite the from address at queue time? My impression is that smtpd_sender_login_maps is used to reject senders (as part of smtpd_sender_restrictions), not to translate logins to email addresses. With this in place, `echo "This is a test" | /usr/sbin/sendmail test@example.com` still queues (and eventually relays) the mail as coming from `user@domU-DE-AD-BE-EF-00-01.compute-1.internal` – John Whitlock Jun 03 '10 at 21:16
  • My bad, I somehow understood you do authorize to your postfix. In such case smtpd_sender_login_maps would limit what user can use what sender adddress. – silk Jun 04 '10 at 11:32
  • This may end up being part of my end solution. I could reject all but the one sender address on the front end, and notify the postmaster of any front end rejections, to let me know when a service isn't configured correctly yet. I'm looking at smtp_generic_maps, to see if I can use them to modify all local accounts to the One True From Address. But, I need to re-read the postfix docs to understand how it determines local accounts - AWS DNS isn't matching my intuition. – John Whitlock Jun 04 '10 at 15:41
  • Is there any way of allowing an e-mail address for all users? Such as: /no-reply@domain.com/ * or OK or something to that effect? I can't seem to get it working. I'm using pcre. – Lethargos Sep 02 '20 at 11:26
0

I use canonical mapping to rewrite the from address, such as rewriting root@app01 to no-reply@example.com.

  • 4
    Welcome to Server Fault! We really do prefer that answers contain content not pointers to content. Whilst this may theoretically answer the question, [it would be preferable](http://meta.stackexchange.com/q/8259) to include the essential parts of the answer here, and provide the link for reference. – user9517 Dec 12 '12 at 14:43