Sending mail from the Docker container (dockerization of postfix and sasl)

    When I placed the application in the Docker container and tried to send email to the mail server in another Docker container, I encountered an unexpected problem. Postfix mail server by default sends mail to an arbitrary recipient domain only from the local client. All other domains must be registered in the relay_domains parameter, and if the mynetwors parameter is configured correctly, mail will be sent to the domains listed in the relay_domains parameter from the client from mynetwors.

    In principle, this was enough for me, because the application should theoretically send mail to exactly one corporate mail server. But such a solution did not suit me very much, because the task can change at any time. Therefore, I tried to configure sasl authorization, which allows you to send mail to authorized users on an arbitrary domain.


    The first solution I tried to use was to install postfix outside the Docker container and send messages from the client from the Docker container directly to port 25 to it. Of course, disappointment awaited me, because localhhost inside the container has nothing to do with localhost outside the container.

    Therefore it would be necessary to address postfix not through localhost. Yes, and initially the goal was to install everything you need in containers, and not depend on the environment on the server. That is, it was desirable to install postfix in the container.

    An additional advantage of installing postfix inside a container is its complete closeness to the outside world, unless you explicitly publish its port in docker-compose, which is naturally easier to control than exotic parameters in the configuration files of postfix itself.

    In order to be able to access the postfix server that runs inside the container, you need to configure authorization. The most popular solution is sasl authorization. I decided to configure it using sasldb2. As it turned out, there are not many detailed instructions on installing sasl for postfix using sasldb2. Some instructions contained outdated information and did not contain the necessary information. As a result, the first time authorization stubbornly refused to work. As it turned out, two main reasons were: the postfix server’s use of the file system in the sandbox / var / spool / postfix /, which sasl knows nothing about, and the need to distribute the rights to the database file / etc / sasldb2, which the sasl user creates - to user postfix.

    The resulting Dockerfile is quite simple, although I had to tinker with the search for a solution, mainly with user rights, which I will talk about in more detail.

    FROM ubuntu:xenial
    ARG UID
    RUN \
      useradd -u $UID www-arc && \
      apt-get update && apt-get install tzdata && \
      echo Europe/Kiev | tee /etc/timezone && \
      dpkg-reconfigure --frontend noninteractive tzdata && \
      apt-get install -y postfix rsyslog sasl2-bin && \
      postconf -e "mydestination = localhost" && \
      postconf -e "myhostname = example.com" && \
      postconf -e "always_bcc = www-arc@localhost" && \
      postconf -e "smtpd_sasl_auth_enable=yes" && \
      postconf -e "broken_sasl_auth_clients=yes" && \
      postconf -e "smtpd_relay_restrictions=permit_sasl_authenticated,reject_unauth_destination" && \
      postconf -e "smtpd_sasl_security_options = noanonymous" && \
      echo 123456 | saslpasswd2 -c -p -u example.com postfix && \
      ln  /etc/sasldb2 /var/spool/postfix/etc/sasldb2 && \
      adduser postfix sasl && \
      touch /var/log/mail.log
    COPY ./smtpd.conf /etc/postfix/sasl/smtpd.conf
    CMD service rsyslog start && service postfix start && tail -f /var/log/mail.log
    

    ln /etc/sasldb2 /var/spool/postfix/etc/sasldb2By default, postfix works with the file system in the sandbox / var / spool / postfix /. There he will look for a file with the logins / etc / sasldb2. Therefore, we set the link to the / etc / sasldb2 file from the sandbox to the real file. The link should only be hard (without the -s option).

    adduser postfix saslquite understandable and very important action allows postfix to work with the file / var / spool / postfix / etc / sasldb2.

    The rule postconf -e "smtpd_recipient_restrictions=permit_sasl_authenticated,reject_unauth_destination"just allows you to send mail to an arbitrary domain to all authenticated sasl clients.

    Sasl authorization configuration in ./smtpd.conf file:

    log_level: 3
    pwcheck_method: auxprop
    auxprop_plugin: sasldb
    mech_list: PLAIN LOGIN CRAM-MD5 DIGEST-MD5 NTLM
    

    The parameter postconf -e "mydestination = localhost"indicates that the mail for this domain should not be sent further but received on this host. As experience shows, mail servers that should receive mail are often configured incorrectly and lose mail. Sometimes this is critical because may harm business if the mailing contains a client’s application for the purchase of goods or services. Therefore, this configuration is configured to send a copy to the local recipient postconf -e "always_bcc = www-arc@localhost". This recipient is created with the current user ID useradd -u $UID www-arc.

    The current user is defined in the docker-compose configuration:

      postfix:
        build:
          context: ./docker/postfix
          args:
           - UID
        volumes:
          - ./docker/postfix/mail:/var/mail
    

    When building, the current user is transferred from the environment env UID=$UID docker-compose build.

    To connect from another docker container to this service, you must specify postfix (the name of the service from docker-compose.yml) as the host, and the domain name (postfix@example.com) and password. In all cases, the name postfix is ​​optional and configurable.

    Setting up mail on the application side and on the side of the mail service is not even half what needs to be done. All that needs to be done besides this in the domain settings often lies outside the control of the developer or devopa, and some specialist with the rights to edit the domain account. With whom you have to communicate on a damaged phone. While there will be a leisurely dialogue in the style of “hey guys, look at yourself there, this is your back-up” - your ip-address will go to the black lists of different mail services, from where it will be so awkward to exclude them. Therefore, it makes sense to immediately use the services of paid email services, for example, docs.aws.amazon.com/ses/latest/DeveloperGuide/postfix.html. You can integrate with them through the API, but from my point of view it is more reliable to do this through postfix (it is intended for this purpose) by setting the parameter relayhost = [email-smtp.us-west-2.amazonaws.com]:587. For more integration, see the AWS website (link above). On the one hand, they guarantee that your ip will not be blacklisted and your mail in spam, but they themselves can declare you a spammer at any time and block your mail. So that there are no perfect solutions.

    Addition.

    Of course, when solving the problem, I "peeped" how other developers do it in open repositories and learned a lot from these sources. Therefore, I will analyze how some of the configurations solve similar problems.

    For the review, I used the key phrase in a Google search “docker sasl postfix”. Therefore, if someone advises some other repositories, I will include them in this list.

    1) github.com/MarvAmBass/docker-versatile-postfix

    The author did not use the postfix plugin auxprop_plugin: sasldb, but the standard sasl tool pwcheck_method: saslauthd. This is another additional process that runs in the container, and which is not very convenient to configure, because it is off by default. Therefore, the author applies such constructions in his configuration:
    RUN sed -i 's/^START=.*/START=yes/g' /etc/default/saslauthd; \
      sed -i 's/^MECHANISMS=.*/MECHANISMS="shadow"/g' /etc/default/saslauthd
    RUN sed -i 's/^OPTIONS=/#OPTIONS=/g' /etc/default/saslauthd; \
      echo 'OPTIONS="-c -m /var/spool/postfix/var/run/saslauthd"' >> /etc/default/saslauthd
    


    2) github.com/cloudposse/postfix

    Similarly to the previous one pwcheck_method: saslauthd

    3) github.com/floriandejonckheere/docker-postfix

    The author used sasldb2 with the postfix plugin, but disabled the sandbox mechanism: smtp inet n - n - - smtpdand used supervisor to start the processes, thus including it in the container several processes.

    4) github.com/catatnight/docker-postfix
    Like the previous one, the author turned off the sandbox: postconf -F '*/*/chroot = n'and used a supervisor.

    5) github.com/juanluisbaptiste/docker-postfix

    Uses a flat file with passwords: echo "[$SMTP_SERVER]:587 $SMTP_USERNAME:$SMTP_PASSWORD" >> /etc/postfix/sasl_passwd

    6) github.com/container-images/postfix

    Disables the sandboxsed -i 's/^smtp\(\s*\)inet\(.*\)/docker_smtp\1inet\tn\ty\tn\t-\t-\tsmtpd -v/g' "$MASTER"

    As a whole, I do not claim that, for example, disabling the sandbox or linking several processes in one container is a more unsuccessful solution, I just pay attention to how these problems were solved by other authors.

    I would be grateful for the addition of this list of repositories, and I promise to promptly supplement this list according to your comments.

    List of useful literature

    1. Installing and configuring Docker + Docker Compose + Postfix + OpenDKIM on Debian in VScale to send an e-mail with a signature. Vadim Khakulov. December 7, 2016 19:25

    apapacy@gmail.com
    April 8, 2018

    Also popular now: