Customize direct-delivery Postfix configuration

If you have a mail receiver container which requires customised Postfix configuration, this is the topic for you. Herein are described the steps required to set Postfix main.cf configuration variables to whatever your heart desires.

Postfix configuration variables can be set via the container environment. Any environment variable starting with POSTCONF_ will set a Postfix configuration variable named for the rest of the environment variable to the value of the environment variable. For example, if you set the environment variable POSTCONF_always_bcc to bob@example.com, then Postfix will be configured with always_bcc = bob@example.com, which will send a copy of all incoming mail to Bob. Poor Bob.

Procedure

  1. Figure out what configuration variables you want to set, and what values to set them to. This may be done by reading the fine manual, or through recommendations in other Discourse documentation, or otherwise.

  2. Connect to your Discourse server via SSH, grab some root privileges, and head over to where all the discourse-docker configuration lives:

    ssh ubuntu@192.0.2.42
    sudo -i
    cd /var/discourse
    
  3. Open up containers/mail-receiver.yml in your text editor of choice, and swing down to the env: section of the file. Somewhere in there, add entries for the variables you want to add, being careful to not modify anything else, and maintaining appropriate indenting. For example, if we were adding our always_bcc setting, the file might look a bit like this:

    env:
      LANG: en_US.UTF-8
      MAIL_DOMAIN: discourse.example.com
      DISCOURSE_BASE_URL: 'https://discourse.example.com'
      DISCOURSE_API_KEY: abcdefghijklmnop
      DISCOURSE_API_USERNAME: system
    
      POSTCONF_always_bcc: 'bob@example.com'
    

    Once you’re happy with what you’ve added, save and exit your editor.

  4. To load the configuration, you simply have to restart the mail-receiver container (a rebuild is not required):

    ./launcher restart mail-receiver
    

    After a brief spasm, the container should be running again.

  5. Test your changes. Ensure both that what you wanted to have happen has, indeed, happened, and also that nothing you didn’t expect to change hasn’t.

Addendum: adding files to the mail-receiver container

Many Postfix configuration parameters require access to “database files”, which provide key/value information which Postfix uses to make decisions about what do with mail. If you see that a configuration parameter accepts a filename that looks like hash:/some/file, you’ve found a use for database files.

The thing is, Postfix running inside the container needs to be able to get at those files while it’s running, which means you need to either copy those files into the container, or (preferably) put those files into a directory on the host, and then mount that directory as a volume inside the container. These instructions describe the second method.

Once you have completed this procedure, any file you place into /var/discourse/shared/mail-receiver/etc will immediately become visible at /etc/postfix/shared inside the container, and any changes you make to those files will be immediately visible to Postfix.

Here’s how to make it happen.

  1. If you’re not still logged in as root to your Discourse server, do so again:

    ssh ubuntu@192.0.2.42
    sudo -i
    cd /var/discourse
    
  2. Open up containers/mail-receiver.yml in your text editor of choice, and this time head for the volume: section. Underneath the existing definition for the /var/spool/postfix directory, add another one, so that your volume section looks like this:

    volumes:
      - volume:
          host: /var/discourse/shared/mail-receiver/postfix-spool
          guest: /var/spool/postfix
      - volume:
          host: /var/discourse/shared/mail-receiver/etc
          guest: /etc/postfix/shared
    

    Save/exit your editor.

  3. To attach the new volume, you simply have to restart the mail-receiver container (a rebuild is not required):

    ./launcher restart mail-receiver
    

All done!

10 Likes

Matt, do you think that could be possible to enable accounts like admin@domain or info@domain from this Postfix configuration?

I only need to have a couple of addresses for incoming e-mail and I have it working with Discourse but I can’t set accounts (their seem to be blocked by default even though messages are processed).

Thanks for all your guides related.

I’ve just set up a trial Discourse service using Digital Ocean and Mailgun for outgoing e-mail. I have a domain registered with a suitable MX record pointing to the Digital Ocean IP address. Outgoing and incoming e-mail works correctly with Discourse. Replies to topics generate outgoing e-mails to those with notifications set and test users can reply to these e-mails and the posts appear in Discourse. All good so far.

I tried to add the POSTCONF_always_bcc: option as above but it doesn’t seem to work - I suspect the ‘mail-receiver’ part of Discourse is unable to properly send the e-mail via Mailgun, even though the ‘app’ part knows how to - app.yml has the username and password of the Mailgun server in it but I’ve not seen any examples of how to put this information in the mail-receiver settings file.

I know the always_bcc option is being read and acted upon as if I type:

./launcher enter mail-receiver

then run

mailq

I can see a test message I sent message sitting on the queue trying to be delivered. In the “-Sender/Recipient-------” column it has the address from which my test message came, the words “(unknown mail transport error)” and then the e-mail address that I had in the always_bcc setting.

I had hoped to somehow filter incoming messages so that if a message was sent to postmaster@mydomain or admin@mydomain it would get resent out on the public internet, via Mailgun, to my gmail address and not sent to Discourse for processing. This may be what user @matenauta was trying to do.

Any hints appreciated on how to do this!

Hmm. Yes, first you’ll need to configure the mailgun the mail receiver to have some means for delivering mail, as it doesn’t know about the credentials or transport mechanism in app.yml. I think you’ll need to add a more complete configuration as hinted in the next section about mounting volumes, the details of which are beyond the scope of this document.

The simple solution for “how do I deal with postmaster and admin emails” is to create a group for each and add whoever you want to get those emails to that group and they can deal with them as group messages.

2 Likes

Did you mean ‘mail-receiver’ rather than Mailgun? As in teach ‘mail-receiver’ how to speak to Mailgun via the public internet and pass credentials properly to ask it to perform the actual deliveries?

Yes. Sorry about that.

Well yes, that, or in some other fashion, configure the mail-receiver (i.e., Postfix) to deliver mail somehow. I’m mostly of the opinion that if you know how to do that then you might rather just do that rather than use the mail-receiver.

Another solution would be to have some <mail thing> process the mail for domain and forward the rest to the mail receiver, perhaps under some other MX.

Having spent this evening trying numerous combinations I’ve managed to install postfix outside the containers that Discourse runs in and can send e-mail via Mailgun that way from the command line, so I have configured postfix to us Mailgun successfully. I’m still drawing a blank trying to get the settings into the mail-receiver container that will make the relaying work via Mailgun. I’m sure there must be a (simple!) way. I can’t seem to find any logs to find out why messages are getting stuck on the mail queue. Containers weren’t around the last time I used linux (a number of years ago). Is there a way of turning on logging so I can see what communication postfix is trying to attempt so I can figure out where the problem is? Conceptually I would like admin@mydomain, once it has come in, to go straight out to my personal gmail account via Mailgun with category1@mydomain and category2@mydomain etc to get pushed on locally to discourse to use to create posts.

2 Likes

Can we use the mail-receiver outside the Discourse containers in another VPS or Datacenter ?

The idea is to change the Discourse IP Address for more privacy and use external “mail-receiver” working/authentication with Discourse forum.

Yes. I’m doing just that. I’ve got the mail receiver running at digital ocean and discourse on machines on another data center.

Can somebody explain how to do that ? this guy asking for money for even answering me.

What is your question?

Nothing special is required to configure the mail-receiver on any server, as long as it has docker and access to the necessary ports.

I setup the mail-receiver as it’s quick and simple… but when i go to check the handle mails it’s give me 404;

my site is subdomain like; forum.site.com

and in app mail-receiver i have this for the endpoint;

DISCOURSE_MAIL_ENDPOINT: ‘http://forum.site.com/admin/email/handle_mail’

should i rebuild the discourse also ?

If you’re getting 404 then it’s probably that the APi key is wrong.

2 Likes

It’s default api and still give me 404 … i send you in google talk, please check.

1 Like

Configuring SMTP banner?

MXtoobox’s SuperTool reports an issue with the SMTP Banner Check.

Normally, the EHLO banner should match the MAIL_DOMAIN which in turn is supposed to match the reverse DNS pointer (PTR record). So if my mail-receiver runs at discourse.example, then the POSTCONF_myhostname should be discourse.example.

What is the right way to configure the EHLO banner?

My first intuition was to try setting HOSTNAME in mail-receiver.yml so it would replace the original host-mail-receiver.localdomain in /etc/postfix/mail-receiver-environment.json. But this does not change /etc/hostname nor does it change myhostname in the Postfix configuration.

I’m tempted to use POSTCONF_myhostname but I fear it will have unwanted side-effects since $myhostname is used in several places and then it would not match /etc/hostname anymore.

root@host-mail-receiver:/etc/postfix# postconf | grep myhostname
lmtp_lhlo_name = $myhostname
local_transport = local:$myhostname
milter_macro_daemon_name = $myhostname
myhostname = host-mail-receiver.localdomain
myorigin = $myhostname
smtp_helo_name = $myhostname
smtpd_proxy_ehlo = $myhostname
root@host-mail-receiver:/etc/postfix# cat /etc/hostname
host-mail-receiver

There is a setting that Discourse-setup asks for. I can’t remember it’s name and it’s hard to find on my phone. You can look at the source or run it.

The Postfix setting smtp_helo_name changes the name specified in the HELO (or EHLO) command, but that is an outgoing delivery setting, while the SMTP banner is sent when receiving mail. The default hostname specified in that is taken from myhostname, but you can modify the banner to display something different with the smtpd_banner setting.

1 Like

Not sure if this will help others, I was getting a similar problem and this helped me realize that for some reason I had revoked the API key. Once I undid the revoke, the incoming mail was working again.

So thank you for helping me realize it was related to the API key :slightly_smiling_face:

1 Like

Has something maybe changed since this was written? I just found that adding a POSTCONF_smtpd_banner value under env: was absolutely not picked up by multiple restarts. I had to rebuild (./launcher rebuild mail-receiver) to get it to take effect.