docker-library / wordpress

Docker Official Image packaging for WordPress
https://wordpress.org/
GNU General Public License v2.0
1.75k stars 1.05k forks source link

Email does not work #30

Open md5 opened 9 years ago

md5 commented 9 years ago

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.

tianon commented 9 years ago

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 commented 9 years ago

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 commented 9 years ago

@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 commented 9 years ago

@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 commented 9 years ago

using Mailchimp or Mandrill still requires using SMTP

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

md5 commented 9 years ago

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 commented 9 years ago

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

booyaa commented 9 years ago

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 :grinning:

timwsuqld commented 9 years ago

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 commented 9 years ago

@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 commented 9 years ago

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 commented 9 years ago

@booyaa :+1:

pierreozoux commented 9 years ago

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 commented 8 years ago

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 commented 8 years ago

@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 commented 8 years ago

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

robertoandrade commented 8 years ago

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 commented 8 years ago

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 commented 8 years ago

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 commented 8 years ago

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 commented 8 years ago

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

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

nathan-osman commented 8 years ago

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 commented 8 years ago

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

ahansson89 commented 8 years ago

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 commented 8 years ago

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

sashman-jaspin commented 8 years ago

I'm far from an email expert, but we pulled down this repo some time ago and just set up sendmail to work with it. We're actually looking for another solution which centralizes it so we can spam check and rate limit outgoing email, but we've had the sendmail solution up for the better part of a year on production sites. The trick is that you have to fully qualify your host name, which you can pass in from docker and re-install sendmail.

We've totally rewritten the dockerfile/start.sh to use wp-cli, php 7.0 and getting services working in lieu of supervisord, but here are the tweaks for this repo :

[Dockerfile]
# Sendmail Installation
RUN apt-get -y install sendmail

[Start.sh]
/etc/init.d/sendmail start
supervisord -n

You have to make sure the host name of the docker instance is a FQDN. We use the scheme host-dock-{port}.hostingcompany.com. If you set this through docker -h then it will configure the host file that sendmail requires. If you don't do this then sendmail will time out (10 sec), which is probably the problem mentioned earlier in this thread.

michelalbers commented 8 years ago

@sashman-jaspin - Thank you. Did just that in the bitnami/php-fpm container and it works just fine.

qsypoq commented 8 years ago

Managed to get it working with this setup :

But i want to do it without the plugin, i think i'm near the solution proposed by @sashman-jaspin ! Problem : it work with the plugin but not without ! while sendmail is working in the container (command line) i just can't make wordpress using it... I think my solution is in the last part of @sashman-jaspin method (maybe i'm wrong) but i don't fully understand it, can someone ELI5 ?

UPDATE With some tricks i managed to make it work without plugin, also updated my blog post about it, (in french) envoyer des emails avec wordpress sur docker.

pierreozoux commented 8 years ago

Ok, I found an acceptable solution \o/ without anything installed!

The idea is to use a "must use plugin". The advantage is that we don't have to activate it. And it is quiet hidden from the user perspective.

So, this configures SMTP support for WordPress using ENV variables: https://github.com/indiehosters/docker-wordpress/blob/master/run.sh

Should I PR to make this available to everybody?

alessiovmagri commented 8 years ago

I'm trying with hectane as mentioned by @nathan-osman , but it seems that wp still tryes to send emails with mail(). Anyone else has tryed it? I put the link as suggested and set "mail" as host. Also tryed to put the mail container/service endpoint as host. Nothing works...

lazyfrosch commented 8 years ago

@pierreozoux I'm using something similar, but sticking it in wp-config.php

Is there a reason why you use it via an extension?

pierreozoux commented 8 years ago

@lazyfrosch I wanted to put it in wp-config.php, but I saw no way to do it.

Could you show your code? If you have a way to configure SMTP from wp-config, then this would be amazing!

lazyfrosch commented 8 years ago

@pierreozoux At the end of wp-config:

// configure phpmailer
add_action( 'phpmailer_init', 'mail_relay' );
function mail_relay( $phpmailer ) {
    $phpmailer->isSMTP();
    $phpmailer->Host = '1.1.1.1';
    $phpmailer->SMTPAutoTLS = false;
    //$phpmailer->SMTPAuth = true; // Force it to use Username and Password to authenticate
    //$phpmailer->Port = 25;
    //$phpmailer->Username = 'yourusername';
    //$phpmailer->Password = 'yourpassword';

    // Additional settings
    //$phpmailer->SMTPSecure = "tls"; // Choose SSL or TLS, if necessary for your server
    //$phpmailer->From = "you@yourdomail.com";
    //$phpmailer->FromName = "Your Name";
}

I'm only setting a relay host, it's the host system running Debian. I'm just trusting my Docker containers as of now.

pierreozoux commented 8 years ago

@tianon what do you think of a PR to ease smtp configuration inside the container via env variables?

Or do you think it would be more suitable to add this in the documentation?

Either way, I think we need to do something to close this issue.

nathan-osman commented 8 years ago

@alessiovmagri oh my! You're right, there seems to be a bug with the latest release of the WordPress plugin. I'll have that fixed immediately and let you know when the update is published.

tianon commented 8 years ago

I'm +1 to documenting this better, especially if there's a good plugin or two we can link to. :smile:

nathan-osman commented 8 years ago

@alessiovmagri sorry about that. The latest version of the plugin (0.1.6) fixes the bug and your container should be able to send emails again.

@tianon let me know if you are interested in mentioning the Hectane plugin - I'd be happy to write up some documentation for using it with the WordPress container if needed.

damiandennis commented 7 years ago

not sure how to get it working with this image but to get it working with the default php image I changed the default CMD in my Dockerfile to

FROM php:5.6-apache
RUN apt-get update && apt-get install -y sendmail
CMD /usr/sbin/service sendmail restart && /usr/local/bin/apache2-foreground

It would be something similar for this image, The main reason is hostname is not set until the container is running.

ebreton commented 7 years ago

thanks @lazyfrosch for the code. I found this solution the most efficient and also the cleanest.

Would that help any one whishing to use a gmail account: you would need to create an "application password", somewhere around here: https://security.google.com/settings/security/apppasswords

The working piece of code will look like:

// configure phpmailer
add_action( 'phpmailer_init', 'mail_relay' );
function mail_relay( $phpmailer ) {
    $phpmailer->isSMTP();
    $phpmailer->Host = 'smtp.gmail.com';
    $phpmailer->SMTPAutoTLS = true;
    $phpmailer->SMTPAuth = true; 
    $phpmailer->Port = 465;
    $phpmailer->Username = '<admin email>';
    $phpmailer->Password = '<app password>';

    // Additional settings
    $phpmailer->SMTPSecure = "ssl"; 
    $phpmailer->From = "<admin email>";
    $phpmailer->FromName = "<your name>";
}

Cheers, Manu

vadimshvetsov commented 7 years ago

Hey all, i've opened an answer at Stack Overflow.

Is any good news we will have in image updates or we need to bypass routes?

charafsalmi commented 7 years ago

I hope this comment will help somehow : https://github.com/docker-library/php/issues/135#issuecomment-277199026

alefi87 commented 7 years ago

Has anyone figured out a neat way to solve this without too much overhead? I'd rather have it all baked into a Dockerfile that adds everything that is needed on top, without having to exec into the container and then fiddle with its settings (for automated deploys). Or perhaps I'm overthinking this and a WP plugin is the way to go? Has anyone ever had the need for this container itself to send emails, which a plugin would not resolve?

nathan-osman commented 7 years ago

I've been running two instances of WordPress in production with Hectane for almost a year now with no issues. The WordPress plugin isn't even really needed now that Hectane accepts mail for delivery directly via SMTP.

abrichr commented 6 years ago

To fix this problem, I created the following files:

php.ini:

sendmail_path=sendmail -t -i 

prepare.sh:

echo "Updating /etc/hosts..."
echo "127.0.0.1 $(hostname) localhost localhost.localdomain" >> /etc/hosts
echo "Restarting sendmail..."
service sendmail restart

Dockerfile:

FROM wordpress

# sendmail
RUN apt-get update && apt-get install -y sendmail
COPY ./php.ini /usr/local/etc/php/conf.d/php.ini
COPY ./prepare.sh /prepare.sh
RUN chmod +x /prepare.sh

CMD /prepare.sh && apache2-foreground

The addition to /etc/hosts is to fix sendmail's long startup and execution time.

Hopefully this helps someone!

minostauros commented 6 years ago

Thanks @abrichr for amazingly simple solution. Didn't catch that /etc/hosts was the villain.

janpapenbrock commented 6 years ago

If you'd like to have all the goodness of @abrichr's above post https://github.com/docker-library/wordpress/issues/30#issuecomment-317511836 (thank you!) without messing with several files, here it is all in one single Dockerfile RUN command.

Bonus: Container will stop when hitting Ctrl+C.

FROM wordpress:apache

RUN \
  #
  # Install sendmail
    apt-get update \
 && apt-get install -y --no-install-recommends sendmail \
 && rm -rf /var/lib/apt/lists/* \
  #
  # Configure php to use sendmail
 && echo "sendmail_path=sendmail -t -i" >> /usr/local/etc/php/conf.d/sendmail.ini \
  #
  # Create script to use as new entrypoint, which
  # 1. Creates a localhost entry for container hostname in /etc/hosts
  # 2. Restarts sendmail to discover this entry
  # 3. Calls original docker-entrypoint.sh
 && echo '#!/bin/bash' >> /usr/local/bin/docker-entrypoint-wrapper.sh \
 && echo 'set -euo pipefail' >> /usr/local/bin/docker-entrypoint-wrapper.sh \
 && echo 'echo "127.0.0.1 $(hostname) localhost localhost.localdomain" >> /etc/hosts' >> /usr/local/bin/docker-entrypoint-wrapper.sh \
 && echo 'service sendmail restart' >> /usr/local/bin/docker-entrypoint-wrapper.sh \
 && echo 'exec docker-entrypoint.sh "$@"' >> /usr/local/bin/docker-entrypoint-wrapper.sh \
 && chmod +x /usr/local/bin/docker-entrypoint-wrapper.sh

ENTRYPOINT ["docker-entrypoint-wrapper.sh"]
CMD ["apache2-foreground"]
Julianoe commented 6 years ago

Hi @janpapenbrock as i am quite new to Docker, just to be clear: what would be the steps to make this work? Until now i used a docker-compose.yml. Should i add something like (see inside the code)

version: '3'

services:
   db:
     container_name: ${CONTAINER_DB_NAME}
     image: mysql:5.7
     restart: unless-stopped
     volumes:
        - ${DB_PATH}:/var/lib/mysql
     environment:
       MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
       MYSQL_DATABASE: ${MYSQL_DATABASE}
       MYSQL_USER: ${MYSQL_USER}
       MYSQL_PASSWORD: ${MYSQL_PASSWORD}

   wordpress:
     depends_on:
       - db
     container_name: ${CONTAINER_WP_NAME}
     image: wordpress:${WORDPRESS_IMAGE}
     restart: unless-stopped
     volumes:
       - ${WP_CORE}:/var/www/html
       - ${WP_CONTENT}:/var/www/html/wp-content
     environment:
       WORDPRESS_DB_HOST: ${CONTAINER_DB_NAME}:3306
       WORDPRESS_DB_NAME: ${MYSQL_DATABASE}
       WORDPRESS_DB_USER: ${MYSQL_USER}
       WORDPRESS_DB_PASSWORD: ${MYSQL_PASSWORD}
       WORDPRESS_TABLE_PREFIX: ${WORDPRESS_TABLE_PREFIX}
       VIRTUAL_HOST: ${DOMAINS}
       LETSENCRYPT_HOST: ${DOMAINS}
       LETSENCRYPT_EMAIL: ${LETSENCRYPT_EMAIL}
     build:
      context: .
      dockerfile: Dockerfile
# I added the Dockerfile you suggested as it is
# and added this build part

networks:
    default:
       external:
         name: ${NETWORK}

I'm confortable with docker-compose and setting up containers but i can't make the mail part working on my wordpress containers :/

Julianoe commented 6 years ago

Just to be clear the thing i want the server to be able to is for example send a "forgotten password" email confirmation. No newsletters or anything like that. @abrichr maybe you can guide me a little here. Should i rebuild an image with the info you provided and mount a container with that said image?

janpapenbrock commented 6 years ago

@Julianoe

Yes, it should work. I spotted in your docker-compose.yml you have both image and build defined for wordpress service.

However, I decided to publish this exact image to Docker Hub and I am successfully using it like so:

services:
  wordpress:
    image: hochzehn/wordpress-sendmail:4.9-php7.1-apache

If you have further questions I'm happy to help on Gitter.

ruucm-working commented 6 years ago

@janpapenbrock

it works on my new site!

but I think SPF should be added to domain