Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Email does not work #30

Open
md5 opened this issue Nov 17, 2014 · 96 comments
Open

Email does not work #30

md5 opened this issue Nov 17, 2014 · 96 comments
Labels

Comments

@md5
Copy link
Contributor

md5 commented Nov 17, 2014

As it currently stands, anything in Wordpress that needs to send email is broken. The wp_mail function that is used for sending out email by default is a thin wrapper over PHP's mail function, which defaults to calling /usr/sbin/sendmail -t -i (cf. http://php.net/manual/en/mail.configuration.php). There are php.ini settings for SMTP, but they are only used on Windows.

For my own work based on this image, I've been installing ssmtp and configuring it to use an external relay host for SMTP, but that's clearly not a turnkey solution for everyone. It also looks like there are many Wordpress plugins that provide SMTP support, but I don't think that installing any of them by default in this image seems reasonable.

Perhaps all of this should just be documented, but I wanted to get it on your radar.

@md5 md5 changed the title Broken wp_mail Email does not work Nov 17, 2014
@tianon
Copy link
Member

tianon commented Nov 17, 2014

Yeah... This was a hole we've had on our radar for a long time now, but
didn't have a good solution. Perhaps an actual issue will get some
brainshare going. We thought about something like ssmtp, but there really
is no good solution that'll work for 90% of users out of the box. Email
is hard. :(

@md5
Copy link
Contributor Author

md5 commented Nov 17, 2014

It looks like WP actually uses something called PHPMailer under the hood, which does support SMTP, but it requires a custom hook for configuration: http://codex.wordpress.org/Plugin_API/Action_Reference/phpmailer_init#Examples

@omarabid
Copy link

omarabid commented Jan 2, 2015

@md5 An alternative is to use a service like mailchimp and Mandrill. I know these are paying services, and not on your own service but the good thing (for Mandrill) is that you can opt out at any moment.

My experience is, your server emails will be probably put in SPAM folder. This is not the case for Mandrill.

@md5
Copy link
Contributor Author

md5 commented Jan 2, 2015

@omarabid using Mailchimp or Mandrill still requires using SMTP, which isn't supported out of the box by Wordpress under Linux. As I mentioned in an earlier comment, it would be possible to add one of the WP plugins that supports SMTP, but I don't think it would be reasonable for a generic Wordpress image to include specific plugins.

In my case, I was using ssmtp to connect to Google Apps with a dedicated mail user. This will avoid spam issues just as well as Mandrill. The case you're talking about is likely the default scenario of a PHP app using the local /usr/sbin/sendmail to send its mail out with no relay host settings. In that case, assuming the IP either isn't listed in the domain's SPF records or the IP is part of a spammy netblock, you will indeed have deliverability problems.

@omarabid
Copy link

omarabid commented Jan 3, 2015

using Mailchimp or Mandrill still requires using SMTP

No, otherwise, what's the point of using Mandrill.

@md5
Copy link
Contributor Author

md5 commented Jan 3, 2015

Ok, you're right that you can use Mandrill with their REST API instead of SMTP, but that requires installing this plugin or some other plugin that knows how to use that API.

As for the point of using Mandrill with SMTP, there are a ton of reasons you might want to do that, including open tracking, click tracking, deliverability concerns, email volume, etc. Not of those advantages of the Mandrill service rely on using the REST API.

@omarabid
Copy link

omarabid commented Jan 3, 2015

@md5 I was just suggesting a solution. Obviously, this should be available/fixed for the official Docker repo.

@booyaa
Copy link

booyaa commented Apr 21, 2015

Wondering how modular you can make the smtp solution> A nice implementation that I've seen is this one https://github.com/catatnight/docker-postfix , but it does bolt on TLS and and OpenDKIM. Perhaps it could be paired down to just postfix? I'm assuming it would only be used via container link so you don't need TLS. DKIM is fall back to avoid DNS shenanigans, admittedly not having it or SSP will probably cause some filters to flag you as spammy.

Thoughts? I think it's time to retreat to the lab 😀

@timwsuqld
Copy link

We are using SSMTP to relay to our main mailserver.
We have a php sendmail.ini file that contains the single line:

sendmail_path = /usr/sbin/ssmtp -t

We have a sed in the Dockerfile that changes the mailhub, rewritedomain and removes the hostname line from the ssmtp file (this way it gets the container id as the hostname)

RUN sed -i -e 's/mailhub=mail/mailhub=ourmailrelay.domain/' \
    -e 's/#rewriteDomain=/rewriteDomain=ourdomain/' \
    -e '/hostname=/d' \
    /etc/ssmtp/ssmtp.conf

This works really well, and as ssmtp isn't a daemon, it doesn't require any process management

@md5
Copy link
Contributor Author

md5 commented Apr 21, 2015

@booyaa I don't like that the Postfix container you mention is using supervisord and running its own rsyslog, but that's a moot point probably.

I think the real issue is that PHP is still going to expect a working sendmail-compatible command which will need to be configured to talk to the linked SMTP container (whether it's postfix or some other SMTP server). Getting such a setup working and maintaining it would be error prone.

I still think the best that can be done here without assuming too much is simply to document the options.

@booyaa
Copy link

booyaa commented Apr 22, 2015

Random musing: this problem would be a great candidate for a mail service docker-compose.yml firing up smtp, imap, spam assassin, clamav and webmail

@md5
Copy link
Contributor Author

md5 commented Apr 22, 2015

@booyaa 👍

@pierreozoux
Copy link

One good option is to configure SSMTP with ENV variables.
This way, you could put your GMAIL or Mandrill cred, and it would work out of the box!

@kcmerrill
Copy link

If this is an old post, or there has previously been a resolution please disregard.

One quick way of getting mail working inside the container is to install msmtp.

Then, in a configuration file(example: msmtp):

account default
host 172.17.42.1
auto_from on

Copy this to /etc/ inside the container

Update the php.ini or set the sendmail_path variable like so:

sendmail_path = "/usr/bin/msmtp -t -i"

TL;DR
Use msmtp to point to the guest machine or some other container.

@omarabid
Copy link

@md5 Any updates on this? I like the new container for SMTP approach. It separates concerns. However, this seems like a WordPress issue for me.

@md5
Copy link
Contributor Author

md5 commented Jul 28, 2015

@omarabid I'm not aware of any developments on this issue other than what you can read in this thread.

@robertoandrade
Copy link

Perhaps since a bunch of you have been able to successfully run ssmtp in the container alongside Wordpress, I thought I'd pose the question here. My install, even after properly configuring /etc/ssmtp/ssmtp.conf with the main SMTP server to relay to still errors out.

Via a simple mail() function test it fails, via wp_mail as well. When I try sendmail from the command line (inside the container) it locks after sending the last <CR>.<CR> and after a timeout period errors with sendmail: Cannot open server-address:port, which matches what I have in the .conf file. I'm using SSL on the other endpoint so wondering if that could play any part in the issue.

@md5
Copy link
Contributor Author

md5 commented Aug 26, 2015

Have you tried telnet server-address port to see if that hangs as well?

Try something like this:

$ docker run -t --rm debian:jessie 'apt-get update && apt-get install -y telnet && telnet server-address port'

If that hangs too, then the problem is probably being caused by firewall rules on the host (outside the container). This can happen if the server you're trying to contact is on an RFC 1918 private subnet like something under 192.168.0.0/16 and your host thinks it should drop packets from the Docker bridge network.

@robertoandrade
Copy link

Yeah, did it, and it works fine. it responds. so don't think it's networking related.

Anyways ended up ditching ssmtp completely on the container and just configured WordPress to use the external mailer directly via a plugin that intercepts the calls to mail(): http://coffee2code.com/wp-plugins/configure-smtp/

@md5
Copy link
Contributor Author

md5 commented Aug 26, 2015

That's odd. I haven't seen sendmail time out for reasons other than packet drops, but perhaps the SMTP server was overloaded or something?

It would be good to get to the bottom of the issue if only for the sake of other users who hit problems using ssmtp.

BTW, I should point out that sendmail inside the container will be a symlink to ssmtp if that's all you have installed.

@pierreozoux
Copy link

Ok, just to continue the discussion, here is a working example with ssmtp configured with env variables:

https://github.com/indiehosters/wordpress/

@nathan-osman
Copy link

So I've managed to come up with a solution that involves another container and a WordPress plugin. The container is running an SMTP client that I wrote (named Hectane) and the WordPress plugin routes all calls to wp_mail() through the container.

Here are the commands to get it up and running:

docker run -d --name db mysql:latest
docker run -d --name mail hectane/hectane:0.2.1
docker run \
    -d -P \
    --link db:db \
    --link mail:mail \
    wordpress:latest

Once the containers are up and running, it's simply a matter of installing and activating this WordPress plugin and changing the hostname to "mail" in "Settings".

WordPress Configuration

Once that's done, all emails will be sent through Hectane and delivered via SMTP.

@joao-parana
Copy link

Hi @nathan-osman, is it possible use hectane/hectane container with Drupal 8 ?

@ahansson89
Copy link

I am using SendGrid for emails. It is super easy to set up with one of the many WP plugins and then you will send emails through an API while getting insights on open rate, bounce rate etc.

@geekscrapy
Copy link

I presume you could use anyone of the smtp plugins to get this to work?
E.g. https://wordpress.org/plugins/wp-smtp/

@JoelLinn
Copy link

Don't use ssmtp on new setups. It isn't serviced and debian packages are orphaned. Use msmtp instead.

/etc/msmtprc

# Set default values for all following accounts.
defaults
auth           on
tls            on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
logfile        /tmp/msmtp.log

# Custom Mailserver
account        mymailserver
host           mail.example.com
port           587
from           [email protected]
user           [email protected]
password       12345678

# Set a default account
account default : mymailserver

With recent versions (not yet available in alpine and debian) you can also set set_from_header to overwrite wordpress@localhost from address.

Also set this php configuration value:
sendmail_path = "/usr/bin/msmtp -t"

@Adrien-Luxey
Copy link

Adrien-Luxey commented Apr 28, 2020

I agree with the above. Let me propose my simple configuration that only forwards mail to my host's postfix (you could also have a dedicated container for sending mail, which would alleviate the need for fixed container network configuration):

/etc/msmtprc (container)

account default
host 172.27.0.1 # IP of my host: the network's gateway from the container's point of view
port 25
from [email protected]

You also need to configure your host's postfix to accept requests from docker:

/etc/postfix/main.cf (host)

# [...]
mynetworks = ... 172.27.0.0/24

This is minimal: expect your mails to end in spam folders. But it works!
Your comments are welcome.

EDIT: I ran into trouble setting mynetworks = ... 172.0.0.0/8. Be specific with your network addresses!

@wpdiaries
Copy link

wpdiaries commented Jul 4, 2020

I had the same problem. So I tried to find a solution. I've found several solutions and tested all of them at my site (to make sure they worked). It would be too long to post them here. So I have created a separate article:

https://www.wpdiaries.com/mail-functionality-for-official-docker-wordpress-image/

The article contains detailed examples of adding Postfix in a separate container. There are 2 such examples based on 2 different images (one has digital signing e-mails with DKIM and the other one works without DKIM). Also, I have added an example of adding Postfix directly to a WordPress container, but this solution is not recommended (it is better to have 1 responsibility for 1 container as it is described in the official Docker best practices).

I've made sure the e-mail sending functionality works in each of the listed examples.

I hope this will be useful for people who got problems with sending e-mail from WordPress in Docker. At least I did my best to provide as detailed and clear examples as I could.

@benhadad
Copy link

possibly use Mailhog? Other images have used this
dockerfile:

Forward Message to mailhog

RUN curl --location --output /usr/local/bin/mhsendmail https://github.com/mailhog/mhsendmail/releases/download/v0.2.0/mhsendmail_linux_amd64 &&
chmod +x /usr/local/bin/mhsendmail
RUN echo 'sendmail_path="/usr/local/bin/mhsendmail --smtp-addr=mailhog:1025 --from=[email protected]"' > /usr/local/etc/php/conf.d/mailhog.ini

docker-compose:
mailhog:
container_name: ${APP_NAME}-mailhog
image: mailhog/mailhog
ports:
- "8025:8025"
- "1025:1025"

@joeldeteves
Copy link

joeldeteves commented Feb 9, 2021

I would consider msmtp instead. It is probably a little better than ssmtp, because ssmtp afaik is unmaintained.

https://marlam.de/msmtp/
https://wiki.archlinux.org/index.php/msmtp

Hello, I have found a much better solution than using msmtp, ssmtp, mailhog or any other SMTP client for that matter.

Wordpress is apparently bundled with PHPMailer - I did not realize that it came included with Wordpress by default.

This means with a little creativity we are able to configure it using the WORDPRESS_CONFIG_EXTRA environment variable that is baked into the docker image.

Here is an example written in YAML for our Kubernetes deployment:

          env:
            - name: SMTP_HOSTNAME
              value: "smtp.office365.com"
            - name: SMTP_PORT
              value: "587"
            - name: SMTP_USER
              value: "[email protected]"
            - name: SMTP_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: "wordpress-smtp-password"
                  key: smtp-password
                  optional: true
            - name: SMTP_FROM
              value: "[email protected]"
            - name: WORDPRESS_CONFIG_EXTRA
              value: |
                // SMTP Settings
                require_once( ABSPATH .'wp-includes/plugin.php' );
                add_action( 'phpmailer_init', 'mail_smtp' );
                function mail_smtp( $phpmailer ) {
                  $phpmailer->isSMTP();
                  $phpmailer->Host = getenv('SMTP_HOSTNAME');
                  $phpmailer->Port = getenv('SMTP_PORT');
                  $phpmailer->Username = getenv('SMTP_USER');
                  $phpmailer->Password = getenv('SMTP_PASSWORD');
                  $phpmailer->From = getenv('SMTP_FROM');
                  $phpmailer->FromName = getenv('SMTP_FROM_NAME');

                  // Additional settings
                  $phpmailer->SMTPAuth = true;
                  $phpmailer->SMTPSecure = "tls";
                  $phpmailer->SMTPAutoTLS = true;
                }
                // Prevent Wordpress from overriding the SMTP FROM address (Office 365 compatibility)
                add_filter( 'wp_mail_from', function( $email ) {
                  return $_ENV["SMTP_FROM"];
                });

Of course, with a little tweaking you can apply the same setup in Docker, docker-compose and more, and at least in our case this eliminates the need for building a custom Docker image or running an MTA in a separate container.

Hope this helps,

@derspotter
Copy link

I would consider msmtp instead. It is probably a little better than ssmtp, because ssmtp afaik is unmaintained.
https://marlam.de/msmtp/
https://wiki.archlinux.org/index.php/msmtp

Hello, I have found a much better solution than using msmtp, ssmtp, mailhog or any other SMTP client for that matter.

Wordpress is apparently bundled with PHPMailer - I did not realize that it came included with Wordpress by default.

This means with a little creativity we are able to configure it using the WORDPRESS_CONFIG_EXTRA environment variable that is baked into the docker image.

Here is an example written in YAML for our Kubernetes deployment:

          env:
            - name: SMTP_HOSTNAME
              value: "smtp.office365.com"
            - name: SMTP_PORT
              value: "587"
            - name: SMTP_USER
              value: "[email protected]"
            - name: SMTP_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: "wordpress-smtp-password"
                  key: smtp-password
                  optional: true
            - name: SMTP_FROM
              value: "[email protected]"
            - name: WORDPRESS_CONFIG_EXTRA
              value: |
                // SMTP Settings
                require_once( ABSPATH .'wp-includes/plugin.php' );
                add_action( 'phpmailer_init', 'mail_smtp' );
                function mail_smtp( $phpmailer ) {
                  $phpmailer->isSMTP();
                  $phpmailer->Host = getenv('SMTP_HOSTNAME');
                  $phpmailer->Port = getenv('SMTP_PORT');
                  $phpmailer->Username = getenv('SMTP_USER');
                  $phpmailer->Password = getenv('SMTP_PASSWORD');
                  $phpmailer->From = getenv('SMTP_FROM');
                  $phpmailer->FromName = getenv('SMTP_FROM_NAME');

                  // Additional settings
                  $phpmailer->SMTPAuth = true;
                  $phpmailer->SMTPSecure = "tls";
                  $phpmailer->SMTPAutoTLS = true;
                }
                // Prevent Wordpress from overriding the SMTP FROM address (Office 365 compatibility)
                add_filter( 'wp_mail_from', function( $email ) {
                  return $_ENV["SMTP_FROM"];
                });

Of course, with a little tweaking you can apply the same setup in Docker, docker-compose and more, and at least in our case this eliminates the need for building a custom Docker image or running an MTA in a separate container.

Hope this helps,

does anyone know how to translate this into a docker-compose.yml? Thank you so much!

@joeldeteves
Copy link

does anyone know how to translate this into a docker-compose.yml? Thank you so much!

Hi @derspotter, you could try something like this (note the double $$ to prevent docker compose from interpreting environment variables in the PHP code):

(NOTE: I do not use Docker compose and I don't know the best way to handle storing sensitive info such as secrets. This is just a proof of concept showing how to translate a quick setup to a docker-compose file:

version: "3.9"
services:
  wordpress:
    image: wordpress:latest
    ports:
      - 8080:80
    environment:
      SMTP_HOSTNAME: smtp.office365.com
      SMTP_PORT: "587"
      SMTP_USER: [email protected]
      SMTP_PASSWORD: /run/secrets/smtp_password
      SMTP_FROM: [email protected]
      WORDPRESS_DB_HOST: wordpress-db
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: /run/secrets/db_password
      WORDPRESS_DB_NAME: wordpress
      WORDPRESS_CONFIG_EXTRA: |
          // SMTP Settings
          require_once( ABSPATH .'wp-includes/plugin.php' );
          add_action( 'phpmailer_init', 'mail_smtp' );
          function mail_smtp( $$phpmailer ) {
              $$phpmailer->isSMTP();
              $$phpmailer->Host = getenv('SMTP_HOSTNAME');
              $$phpmailer->Port = getenv('SMTP_PORT');
              $$phpmailer->Username = getenv('SMTP_USER');
              $$phpmailer->Password = getenv('SMTP_PASSWORD');
              $$phpmailer->From = getenv('SMTP_FROM');
              $$phpmailer->FromName = getenv('SMTP_FROM_NAME');

              // Additional settings
              $$phpmailer->SMTPAuth = true;
              $$phpmailer->SMTPSecure = "tls";
              $$phpmailer->SMTPAutoTLS = true;
  
              // Filter out client message body and output debug info to the logs
              // NOTE: Log level must be set to '2' or higher in order for the filter to work
              $$phpmailer->SMTPDebug = 2;

              $$phpmailer->Debugoutput = function($$str) {
                  static $$logging = true;
                  if ($$logging === false && strpos($$str, 'SERVER -> CLIENT') !== false) {
                      $$logging = true;
                  }
                  if ($$logging) {
                      error_log("SMTP " . "$$str");
                  }
                  if (strpos($$str, 'SERVER -> CLIENT: 354') !== false) {
                      $$logging = false;
                  }
              };
          }
          // Prevent Wordpress from overriding the SMTP FROM address (Office 365 compatibility)
          add_filter( 'wp_mail_from', function( $$email ) {
              return $$_ENV["SMTP_FROM"];
          });
    volumes:
      - wp-data:/var/www/html
    secrets:
      - db_password
      - smtp_password
    depends_on:
      - wordpress-db
    
  wordpress-db:
    image: mariadb:latest
    environment:
      MYSQL_ROOT_PASSWORD: /run/secrets/db_root_password
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: /run/secrets/db_password
    volumes:
      - db-data:/var/lib/mysql
    secrets:
      - db_root_password
      - db_password

volumes:
  wp-data:
  db-data:

secrets:
  db_password:
    file: db_password.secret
  db_root_password:
    file: db_root_password.secret
  smtp_password:
    file: smtp_password.secret

@derspotter
Copy link

does anyone know how to translate this into a docker-compose.yml? Thank you so much!

Hi @derspotter, you could try something like this (note the double $$ to prevent docker compose from interpreting environment variables in the PHP code):

Thank you so much!!! it works :))

@dont-panic-42
Copy link

Thanks @joeldeteves for the WORDPRESS_CONFIG_EXTRA + PHPMailer solution, it is working for me.

In case it saves someone else a few frustrating hours, it seems like the *-alpine Docker WP images are not able to do external networking (like connecting to remote external SMTP hosts). I'm talking about external connections to public internet hosts (like smtp.mailgun.org), not to your local Docker containers. Maybe that's common knowledge but it was news to me.

I am not sure what exactly is missing but from inside a container using the wordpress:5.6-php7.4-fpm-alpine image, I was not able to either resolve an IP for my mail host (smtp.mailgun.org), nor ping it. Switching to wordpress:5.6-php7.4-fpm solved the problem, though it took much hair pulling and gnashing of teeth to get there.

@joeldeteves
Copy link

joeldeteves commented Mar 14, 2021

it seems like the *-alpine Docker WP images are not able to do external networking (like connecting to remote external SMTP hosts)

I'm not able to reproduce this problem; I use alpine versions for all my deployments (currently running wordpress:5.6.2-php7.4-fpm-alpine).

You might want to double-check your config and/or firewall.

@dont-panic-42
Copy link

I'm not able to reproduce this problem; I use alpine versions for all my deployments (currently running wordpress:5.6.2-php7.4-fpm-alpine).

@joeldeteves Interesting. I'm on macOS. It doesn't work for me. I'm not sure this is the right place for this tangent but maybe it is relevant and helps others. Super-simple docker-compose.yml demonstrating the problem:

version: '3'
services:
  wordpress1:
    image: wordpress:5.6-php7.4-fpm
  wordpress2:
    image: wordpress:5.6-php7.4-fpm-alpine
$ docker-compose up -d
Starting test_wordpress1_1 ... done
Starting test_wordpress2_1 ... done

$ docker exec -it test_wordpress1_1 bash
root@36939bbe8fcb:/var/www/html# curl -I https://github.com/docker-library/wordpress/issues/30
HTTP/2 200
server: GitHub.com
date: Sun, 14 Mar 2021 18:12:44 GMT
... lots of headers, clearly works fine
root@36939bbe8fcb:/var/www/html# exit

$ docker exec -it test_wordpress2_1 bash
bash-5.1# curl -I https://github.com/docker-library/wordpress/issues/30
curl: (6) Could not resolve host: github.com

@joeldeteves
Copy link

joeldeteves commented Mar 14, 2021

@joeldeteves Interesting. I'm on macOS. It doesn't work for me. I'm not sure this is the right place for this tangent but maybe it is relevant and helps others.

I still can't reproduce this (I used the compose example you provided above, both containers are able to resolve just fine) however I am running Ubuntu.

It is very probable that this is something specific to your environment, quite possibly Mac-OS specific.

You may want to run some more tests such as testing from a VM, but I do not believe it is related to the alpine image.

@kimlehtinen
Copy link

does anyone know how to translate this into a docker-compose.yml? Thank you so much!

Hi @derspotter, you could try something like this (note the double $$ to prevent docker compose from interpreting environment variables in the PHP code):

(NOTE: I do not use Docker compose and I don't know the best way to handle storing sensitive info such as secrets. This is just a proof of concept showing how to translate a quick setup to a docker-compose file:

version: "3.9"
services:
  wordpress:
    image: wordpress:latest
    ports:
      - 8080:80
    environment:
      SMTP_HOSTNAME: smtp.office365.com
      SMTP_PORT: "587"
      SMTP_USER: [email protected]
      SMTP_PASSWORD: /run/secrets/smtp_password
      SMTP_FROM: [email protected]
      WORDPRESS_DB_HOST: wordpress-db
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: /run/secrets/db_password
      WORDPRESS_DB_NAME: wordpress
      WORDPRESS_CONFIG_EXTRA: |
          // SMTP Settings
          require_once( ABSPATH .'wp-includes/plugin.php' );
          add_action( 'phpmailer_init', 'mail_smtp' );
          function mail_smtp( $$phpmailer ) {
              $$phpmailer->isSMTP();
              $$phpmailer->Host = getenv('SMTP_HOSTNAME');
              $$phpmailer->Port = getenv('SMTP_PORT');
              $$phpmailer->Username = getenv('SMTP_USER');
              $$phpmailer->Password = getenv('SMTP_PASSWORD');
              $$phpmailer->From = getenv('SMTP_FROM');
              $$phpmailer->FromName = getenv('SMTP_FROM_NAME');

              // Additional settings
              $$phpmailer->SMTPAuth = true;
              $$phpmailer->SMTPSecure = "tls";
              $$phpmailer->SMTPAutoTLS = true;
  
              // Filter out client message body and output debug info to the logs
              // NOTE: Log level must be set to '2' or higher in order for the filter to work
              $$phpmailer->SMTPDebug = 2;

              $$phpmailer->Debugoutput = function($$str) {
                  static $$logging = true;
                  if ($$logging === false && strpos($$str, 'SERVER -> CLIENT') !== false) {
                      $$logging = true;
                  }
                  if ($$logging) {
                      error_log("SMTP " . "$$str");
                  }
                  if (strpos($$str, 'SERVER -> CLIENT: 354') !== false) {
                      $$logging = false;
                  }
              };
          }
          // Prevent Wordpress from overriding the SMTP FROM address (Office 365 compatibility)
          add_filter( 'wp_mail_from', function( $$email ) {
              return $$_ENV["SMTP_FROM"];
          });
    volumes:
      - wp-data:/var/www/html
    secrets:
      - db_password
      - smtp_password
    depends_on:
      - wordpress-db
    
  wordpress-db:
    image: mariadb:latest
    environment:
      MYSQL_ROOT_PASSWORD: /run/secrets/db_root_password
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: /run/secrets/db_password
    volumes:
      - db-data:/var/lib/mysql
    secrets:
      - db_root_password
      - db_password

volumes:
  wp-data:
  db-data:

secrets:
  db_password:
    file: db_password.secret
  db_root_password:
    file: db_root_password.secret
  smtp_password:
    file: smtp_password.secret

Thank you this worked with docker-compose! I created a separate gmail account that's only used to send mails on a wp-site of mine. If you use gmail as I did, you have to enable less secure apps in your gmail settings https://support.google.com/accounts/answer/6010255?hl=en

@sceptic30
Copy link

sceptic30 commented May 4, 2021

Hello everyone.
I figured out a clean and working solution without any hacks around WORDPRESS_CONFIG_EXTRA, or wordpress plugins.
It was more of a php issue than wordpress it self.
I work only with alpline images so the packages that needs to be installed are alpine packages.
For extra security the php image will run under www-data.
What i did was:

  1. install msmtp and mailx packages from edge/community repository
  2. create a soft link : ln -sf /usr/bin/msmtp /usr/sbin/sendmail
  3. Apply some permissions needed.
  4. echo 'sendmail_path = "/usr/bin/msmtp -t"' > /usr/local/etc/php/conf.d/msmtp.ini

The exact RUN statement is bellow:

RUN set -x \
    && echo "http://dl-cdn.alpinelinux.org/alpine/edge/community/" >> /etc/apk/repositories \
    && apk add --no-cache \
    msmtp \
    mailx \
    && ln -sf /usr/bin/msmtp /usr/sbin/sendmail \
    && chown 82:82 -R /var/mail \
    && touch /etc/msmtprc \
    && chown 82:82 /etc/msmtprc \
    && chmod 600 /etc/msmtprc \
    && echo 'sendmail_path = "/usr/bin/msmtp -t"' > /usr/local/etc/php/conf.d/msmtp.ini

The exact Php's Dockerfile is here https://github.com/sceptic30/php8-msmtp/blob/main/Dockerfile
Based on that, i created a wordpress image like normally https://github.com/sceptic30/wordpress-php-fpm-redis-alpine/blob/master/Dockerfile

For those that they just want to download the images use these commands (currently the most up to date):

docker pull admintuts/php:7.4.18-fpm-alpine 
docker pull admintuts/php:8.0.5-fpm-alpine

And for Wordpress:

docker pull admintuts/wordpress:php7.4.18-fpm-redis-alpine
docker pull admintuts/wordpress:php8.0.5-fpm-redis-alpine

After that, follow instructions given here https://github.com/sceptic30/php8-msmtp#create-configuration-files-for-msmtp for the confuguration files that needs to be bind-mount to the container file system, and you should be good to go.

@Losmoges
Copy link

Losmoges commented Jul 6, 2021

I have a running dovecot/postfix stack at arbitrary internal hostname dovecot.my for development. With the following php code loaded in wordpress the email functionality is working. Inspired by/copied from posts above.

require_once(ABSPATH .'wp-includes/plugin.php');

// configure phpmailer with SMTP before sending emails
add_action('phpmailer_init', function($mailer) {
  $mailer->isSMTP();
  $mailer->Host = "dovecot.my";
  $mailer->SMTPAuth = true;
  $mailer->Username = "[email protected]";
  $mailer->Password = "pass";
  $mailer->Port = 587;
});

// from_email defaults to 'wordpress@$sitename', which seems to be wordpress@localhost by default
// use this filter to make sure it matches your smtp host
add_filter('wp_mail_from', function($from) {
  return "[email protected]";
});

// optional: error logging in case phpmailer fails
add_action('wp_mail_failed', function($wperror) {
  error_log(implode("; ", $wperror->get_error_messages()));
});

I put the above in a WORDPRESS_CONFIG_EXTRA environment variable in my docker-compose.yml. Just be sure to duplicate all the $ signs so that docker-compose doesn't interpret them as bash/env variables. Note: any other way to add this script to your wordpress would probably work as well. No need to install any additional softwares in my wordpress container.

Just be aware that this is probably terrible security, don't use in production.

Tested on wordpress:5.7.2

@CholoTook
Copy link

If I add a plugin via the settings interface once the container is running, is that persisted? I'm using the example docker-compose.yml, and the only 'external' volume is /var/www/html so I suppose it SHOULDN@T be... However, a quick test with a restart shows that it is... I'm guessing it won't persist a rebuild? Not sure if this is an issue or not...

@tianon
Copy link
Member

tianon commented Nov 29, 2022

As long as you persist /var/www/html and your MySQL database, all your configuration (including content uploads like post attachments and installed plugins) will stay.

@huksley
Copy link

huksley commented Jan 25, 2023

@Losmoges does not work, writes to log sh: 1: /usr/sbin/sendmail: not found
Wordpress 6.1.1

@jmhunter
Copy link

jmhunter commented Mar 6, 2023

If anyone's interested, my approach to solve this was as follows.

In docker-compose.yml:

wordpress:
  [...]
    volumes:
    - /data/docker/mysite/html:/var/www/html
    - /data/docker/mysite/msmtprc:/etc/msmtprc
    - /data/docker/mysite/msmtp-php.ini:/usr/local/etc/php/conf.d/msmtp-php.ini
  # Following is a method of installing msmtp without re-mastering the entire docker image
  #   (inspiration from https://stackoverflow.com/questions/47615751/docker-compose-run-a-script-after-container-has-started )
  # Entrypoint command taken from https://github.com/docker-library/wordpress/blob/master/Dockerfile.template
  command: sh -c "if [ ! -x /usr/bin/msmtp ]; then apt update; DEBIAN_FRONTEND=noninteractive apt -y install msmtp; fi; exec /usr/local/bin/docker-entrypoint.sh apache2-foreground"

msmtp-php.ini:

sendmail_path = "/usr/bin/msmtp -t -i"

msmtprc:

defaults

account mysite
host smtp.myhost.com
from [email protected]

account default: mysite

Seems to work in my very basic testing (I'm a complete Wordpress newbie; have only been looking at this to get a site up and running that somebody has asked me to host).

@na0x2c6
Copy link

na0x2c6 commented Mar 26, 2023

I noticed that I can send emails by wrapping docker-entrypoint.sh and starting the sendmail daemon. I hope this helps someone.

wrapped-entrypoint.sh

#!/bin/bash

# Start the sendmail daemon
/usr/sbin/sendmail -bd

# Execute the original entrypoint script
exec docker-entrypoint.sh "$@"

Dockerfile

FROM docker.io/library/wordpress:php7.4-apache

# Install sendmail
RUN apt-get update && apt-get install -y sendmail && apt-get clean

# Copy the wrapped entrypoint script
COPY wrapped-entrypoint.sh /usr/local/bin/

# Make the script executable
RUN chmod +x /usr/local/bin/wrapped-entrypoint.sh

# Use the wrapped entrypoint
ENTRYPOINT ["wrapped-entrypoint.sh"]

@ja2ui0
Copy link

ja2ui0 commented May 13, 2023

does anyone know how to translate this into a docker-compose.yml? Thank you so much!

Hi @derspotter, you could try something like this (note the double $$ to prevent docker compose from interpreting environment variables in the PHP code):

(NOTE: I do not use Docker compose and I don't know the best way to handle storing sensitive info such as secrets. This is just a proof of concept showing how to translate a quick setup to a docker-compose file:

version: "3.9"
services:
  wordpress:
    image: wordpress:latest
    ports:
      - 8080:80
    environment:
      SMTP_HOSTNAME: smtp.office365.com
      SMTP_PORT: "587"
      SMTP_USER: [email protected]
      SMTP_PASSWORD: /run/secrets/smtp_password
      SMTP_FROM: [email protected]
      WORDPRESS_DB_HOST: wordpress-db
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: /run/secrets/db_password
      WORDPRESS_DB_NAME: wordpress
      WORDPRESS_CONFIG_EXTRA: |
          // SMTP Settings
          require_once( ABSPATH .'wp-includes/plugin.php' );
          add_action( 'phpmailer_init', 'mail_smtp' );
          function mail_smtp( $$phpmailer ) {
              $$phpmailer->isSMTP();
              $$phpmailer->Host = getenv('SMTP_HOSTNAME');
              $$phpmailer->Port = getenv('SMTP_PORT');
              $$phpmailer->Username = getenv('SMTP_USER');
              $$phpmailer->Password = getenv('SMTP_PASSWORD');
              $$phpmailer->From = getenv('SMTP_FROM');
              $$phpmailer->FromName = getenv('SMTP_FROM_NAME');

              // Additional settings
              $$phpmailer->SMTPAuth = true;
              $$phpmailer->SMTPSecure = "tls";
              $$phpmailer->SMTPAutoTLS = true;
  
              // Filter out client message body and output debug info to the logs
              // NOTE: Log level must be set to '2' or higher in order for the filter to work
              $$phpmailer->SMTPDebug = 2;

              $$phpmailer->Debugoutput = function($$str) {
                  static $$logging = true;
                  if ($$logging === false && strpos($$str, 'SERVER -> CLIENT') !== false) {
                      $$logging = true;
                  }
                  if ($$logging) {
                      error_log("SMTP " . "$$str");
                  }
                  if (strpos($$str, 'SERVER -> CLIENT: 354') !== false) {
                      $$logging = false;
                  }
              };
          }
          // Prevent Wordpress from overriding the SMTP FROM address (Office 365 compatibility)
          add_filter( 'wp_mail_from', function( $$email ) {
              return $$_ENV["SMTP_FROM"];
          });
    volumes:
      - wp-data:/var/www/html
    secrets:
      - db_password
      - smtp_password
    depends_on:
      - wordpress-db
    
  wordpress-db:
    image: mariadb:latest
    environment:
      MYSQL_ROOT_PASSWORD: /run/secrets/db_root_password
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: /run/secrets/db_password
    volumes:
      - db-data:/var/lib/mysql
    secrets:
      - db_root_password
      - db_password

volumes:
  wp-data:
  db-data:

secrets:
  db_password:
    file: db_password.secret
  db_root_password:
    file: db_root_password.secret
  smtp_password:
    file: smtp_password.secret

Thanks for this. It seems like this is the most straightforward solution that doesn't involve rebuilding the container, which is a huge plus. Still works perfectly.

@punkyard
Copy link

punkyard commented Jan 8, 2024

does anyone know how to translate this into a docker-compose.yml? Thank you so much!

Hi @derspotter, you could try something like this (note the double $$ to prevent docker compose from interpreting environment variables in the PHP code):

(NOTE: I do not use Docker compose and I don't know the best way to handle storing sensitive info such as secrets. This is just a proof of concept showing how to translate a quick setup to a docker-compose file:

hi, thanks a lot for your solution
do you think you could detail the reason why using secrets and not writing the passwords directly in the compose.yml file as recomanded on WP official docker hub? I'm doing so at the moment in a portainer stack with volumes to /mnt folder.. is it risky according to you? ^^

@LaurentGoderre
Copy link
Member

I think the main reason to avoid putting secrets in the docker-compose yaml is to prevent accidentally committing a real secret in source control.

@comzeradd
Copy link

In order to work around the issue I created a very simple plugin that just expects certain SMTP variables to exist in wp-config.php.

Then all it takes is adding the plugin to the proper place (wp-content/plugins) in the volume mounted in docker-compose and add the secrets to wp-config.php, which should be in .gitignore anyway to avoid pushing secrets to a public repository.

@mariusklocke
Copy link

mariusklocke commented Nov 27, 2024

I stumbled upon this issue today. I took a look into the sendmail executable provided by busybox (already contained in Alpine-based images). It's a bit tricky to get support for SMTP over TLS, but I got it working. So I wanna share my solution here.

SSL support in sendmail by busybox is available by feeding it a helper script with openssl s_client. Because PHP seems to have trouble with quotes inside the sendmail_path in php.ini files, I created a simple shell script wrapper. Feel free to adjust it to your needs.

#!/bin/sh
SENDER_ADDRESS="[email protected]"
SMTP_HOST="smtp.example.com:465"
SMTP_USERNAME="[email protected]"
SMTP_PASSWORD="p4ssw0rd"

/usr/sbin/sendmail \
  -t \
  -H "openssl s_client -quiet -connect $SMTP_HOST" \
  -au$SMTP_USERNAME \
  -ap$SMTP_PASSWORD \
  -f $SENDER_ADDRESS

Please note that there MUST NOT be a whitespace character before username and password. I saved the previous script on my docker host and mounted it to /usr/local/bin/sendmail inside the wordpress container. My php.ini also resides on the host machine and mounts to /usr/local/etc/php/php.ini inside the wordpress container. Add the following line to your php.ini:

sendmail_path=/usr/local/bin/sendmail

This works for me without any further Wordpress configuration. If you are worried about passing the password on CLI: sendmail by busybox can also read the credentials from a file. To use this feature write your username and password to a file (separated by newline character) and feed it to /usr/sbin/sendmail as File Descriptor 4:

#!/bin/sh
SENDER_ADDRESS="[email protected]"
SMTP_HOST="smtp.example.com:465"

/usr/sbin/sendmail \
  -t \
  -H "openssl s_client -quiet -connect $SMTP_HOST" \
  -amLOGIN 4<user_pass.txt \
  -f $SENDER_ADDRESS

AFAIK sendmail by busybox does NOT support loading a regular config file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests