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

mail() does not work out of the box #135

Closed
NitroPye opened this issue Sep 16, 2015 · 27 comments

Comments

Projects
None yet
@NitroPye
Copy link

commented Sep 16, 2015

It seems that the sendmail_from config setting isn't right? If additional configuration is required for this to work should this be noted in the documentation?

When running php -i | grep sendmail_path I get this

php -i | grep sendmail_path
sendmail_path =>  -t -i  =>  -t -i 

When running this script

<?php 
mail('test@example.com', 'Subject', 'Body');
?>

The results are this:

sh: 1: -t: not found
@md5

This comment has been minimized.

Copy link
Contributor

commented Sep 17, 2015

The docs say this:

Where the sendmail program can be found, usually /usr/sbin/sendmail or /usr/lib/sendmail. configure does an honest attempt of locating this one for you and set a default, but if it fails, you can set it here.

Looks like configure is failing to set a value for sendmail_path since there is no sendmail binary installed when PHP is built.

@NitroPye

This comment has been minimized.

Copy link
Author

commented Sep 17, 2015

I ended up trying to add sendmail or postfix to a container extending from php:5.6-apache and pointing the php.ini sendmail_path to them correctly but ran into the problem of multiple services running inside the container.

Ended up settling on using ssmtp to solve this. Here is a Dockerfile that should work with mail() out of the box.

FROM php:5.6-apache

RUN apt-get update && \
  apt-get install -y ssmtp && \
  apt-get clean && \
  echo "FromLineOverride=YES" >> /etc/ssmtp/ssmtp.conf && \
  echo 'sendmail_path = "/usr/sbin/ssmtp -t"' > /usr/local/etc/php/conf.d/mail.ini

mail() should work out of the box with this container. I'm not sure if this is something that should be modified and changed in the base php container or documented somewhere. Thoughts?

@md5

This comment has been minimized.

Copy link
Contributor

commented Sep 17, 2015

I don't think it's possible to have a reasonable default configuration for mail(). In the case of ssmtp, you need to point it at an SMTP server (likely providing credentials). Trying to use an actual MTA like Postfix or Sendmail means that multiple services will be running in the container, as you mention.

Given that, I think that documenting the issue and possible ways to fix it is the best that can be done.

I previously opened an issue for the wordpress image where users have mentioned other configurations they've used to get mail() working: docker-library/wordpress#30

@NitroPye

This comment has been minimized.

Copy link
Author

commented Sep 17, 2015

Good points. Seems the most Docker-like way to do this would be to have two containers, the php one and a MTA one, have ssmtp setup in the php one linked to the MTA one. Not the easiest thing in the world to document in a general manner. I'll close this for now since it doesn't seem like there are any actions that can be taken. Thanks for the insight.

@NitroPye NitroPye closed this Sep 17, 2015

@md5

This comment has been minimized.

Copy link
Contributor

commented Sep 17, 2015

This PHP feature request is relevant (enable direct SMTP support on non-Windows systems), though it doesn't seem like they'll ever implement it: https://bugs.php.net/bug.php?id=29629

@stuartz-VernonCo

This comment has been minimized.

Copy link

commented Jan 29, 2016

It took me way too much time to research and empliment. Hope this helps someone else.

for simple solution that may be filtered by spam filters:
for more details, information used from: [http://www.tothenew.com/blog/setting-up-sendmail-inside-your-docker-container/]

Dockerfile bare-bones example:
FROM php:apache
'#' debian:jessie, apache on port 80, php:latest
'#' retrieve needed system programs
RUN apt-get update && apt-get upgrade -y sendmail && rm -rf /var/lib/apt/lists/*
COPY ./app/ /var/www/html/
'#' to be ran with docker exec later
COPY ./config_files/mail_config.sh /var/www'
'#' php:apache recommends using your own php.ini
COPY ./config_files/php.ini /usr/local/etc/php/php.ini

.config_files/mail_config.sh example:
line=$(head -n 1 /etc/hosts)
line2=$(echo $line | awk '{print $2}')
echo "$line $line2.localdomain" >> /etc/hosts
/etc/init.d/sendmail start
sleep 1
service apache2 graceful

add to your ./config_files/php.ini:
sendmail_path = /usr/sbin/sendmail -t -i

Then run the following to initiate it after starting container
or put as a CMD in Dockerfile if yours doesn't already have a CMD.

docker exec container_name bash /var/www/mail_config.sh

EDIT May 16, 2019

added ability to send as desired domain (see replace MASQUERADE_AS)

previous EDIT Feb 10,2017

I had another program that was editing the /etc/hosts file at start up, and so I changed my mail_config.sh The change also made it possible to not have to edit /etc/mail/sendmail.mc to remove localhost access thanks to a hint from @charafsalmi.

** /mail_config.sh

#!/bin/sh
#add host to /etc/hosts
host=$(hostname)
line=$(cat /etc/hosts |grep [1]27.0.0.1)
#placed at end to prevent being changed by weave
echo "$line noreply@yourdomain.com $host" >> /etc/hosts

#or if file is not being changed by other applications
#sed -i -e "s/$line/$line noreply@yourdomain.com $host/g" /etc/hosts

#finally
echo "$host" >> /etc/mail/relay-domains
replace MASQUERADE_AS with your domain to have it send mail out as the desired domain
line=$(cat /etc/mail/sendmail.mc | grep [M]ASQUERADE_AS)
's/^"$line".*/MASQUERADE_AS(`YOURDOMAIN.COM')dnl/' /etc/mail/sendmail.mc
m4 /etc/mail/sendmail.mc > /etc/mail/sendmail.cf
#start service
service sendmail restart # or sendmail -bd

@charafsalmi

This comment has been minimized.

Copy link

commented Feb 2, 2017

@stuartz-VernonCo do you know wether there is anything more to do to get it working with docker php-fpm or not ?

Everytime I send a mail I get a 504 error.

@stuartz-VernonCo

This comment has been minimized.

Copy link

commented Feb 2, 2017

@charafsalmi Time out waiting for a response (504) could be an issue with firewall not allowing the connection back in, or on AWS not allowing emails to be sent out on port 25 to prevent spam. Could be a number of things. On AWS, I used a queue on a database for applications sending out email, and smtp the emails through our office365.
Have you tried the container inside your LAN to send to a local email? Remove the network obstacles and if it works, focus on the network rules that are keeping it from working else where.

@charafsalmi

This comment has been minimized.

Copy link

commented Feb 3, 2017

@stuartz-VernonCo thank you !

it took me wayyyy so much time to find out why it wasn't working… it was not about the firewall, it was about what sendmail is expecting us to put in /etc/hosts

The last line of /etc/hosts has to contain this structure : [IP] "your.domain.com" [HOSTNAME]

So, once I changed my /etc/hosts to 127.0.0.1 noreply.domain.com e0dd810b0efd and restarted docker, it worked.

It's sad that sendmail doesn't give any clue about this.

# echo "127.0.0.1 noreply.domain.com $(hostname)" >> /etc/hosts

@getvivekv

This comment has been minimized.

Copy link

commented Feb 8, 2017

@charafsalmi You are a lifesaver.

@partounian

This comment has been minimized.

Copy link

commented Apr 5, 2017

Just to confirm @charafsalmi all we need to do is run that last line on our docker container?

@charafsalmi

This comment has been minimized.

Copy link

commented Apr 7, 2017

@partounian Yes sir.

@m0onspell

This comment has been minimized.

Copy link

commented Jul 30, 2017

It wasn't enough for me. I had to add

RUN sed -i 's@local@internet@' /etc/exim4/update-exim4.conf.conf \
  && update-exim4.conf

to be able to send emails to external addresses (like gmail).

But even after that, I am still getting errors in /var/log/exim4/mainlog

SMTP error from remote mail server after end of data: The IP you're using to send mail is not authorized to\n550-5.7.1 send email directly to our servers. 
Please use the SMTP relay at your\n550-5.7.1 service provider instead. 
Learn more at\n550 5.7.1  https://support.google.com/mail/?p=NotAuthorizedError

It's probably not in the scope of this issue, since mail function is working, it's more about sendmail configuration.
But that's something to be aware of.

@adriansecretsource

This comment has been minimized.

Copy link

commented Dec 29, 2017

@m0onspell You just saved my day!

I had problems trying to configure exim4 on a Rails Docker container to be able to send emails, but your code just did the trick.

Now its working with this commands.

RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs exim4
RUN sed -i 's@local@internet@' /etc/exim4/update-exim4.conf.conf \
  && update-exim4.conf
...
@drewwestphal

This comment has been minimized.

Copy link

commented Jan 26, 2018

I solved this problem with MSMTP, sendgrid (works for us, you could pick another service, obv) and some environment variables, which I believe is pretty lightweight. I stumbled across this thread and the answers here helped me, so here's what I did for the next person:

DOCKERFILE

RUN apt-get update && apt-get install -y msmtp && apt-get clean && rm -r /var/lib/apt/lists/*
# configure sendmail
RUN { \
    	echo "php_admin_value[sendmail_path] = $(which msmtp) -ti "; \
    } >> /usr/local/etc/php-fpm.d/www.conf

# configure entrypoint
COPY fpm-entrypoint.sh /usr/local/bin
ENTRYPOINT ["fpm-entrypoint.sh"]

ENTRYPOINT

#!/bin/bash
set -euo pipefail

cat >> /etc/msmtprc <<-EOCFG
account         default
host         smtp.sendgrid.net
port         587
timeout         30
auth         on
tls          on
tls_starttls    on
tls_trust_file     /etc/ssl/certs/ca-certificates.crt
syslog          on

auto_from       off
user         ${MTA_SENDGRID_USER}
password        ${MTA_SENDGRID_PASS}
from         ${MTA_SENDGRID_FROM}
maildomain      ${MTA_SENDGRID_MAILDOMAIN}
EOCFG


exec "$@"
@LaQuay

This comment has been minimized.

Copy link

commented Feb 5, 2018

@stuartz-VernonCo Thanks!

Also, if you are having problems if the docker-container is always restarting after doing what he says, just make sure to call your php server again

Example, this inside the Dockerfile:
CMD /var/www/mail_config.sh && php-fpm

@michelalbers

This comment has been minimized.

Copy link

commented Feb 9, 2018

Well here is my simple solution:

Dockerfile (for your custom php image)

FROM php:fpm
RUN apt-get update && apt-get install -y sendmail
ADD ./php.sh /opt/php.sh
ADD sendmail.ini /usr/local/etc/php/conf.d/
RUN chmod u+x /opt/php.sh
WORKDIR /opt
CMD ["php.sh"]

sendmail.ini

# Enable sendmail
sendmail_path = "/usr/sbin/sendmail -t -i"

php.sh

#! /bin/sh
line=$(head -n 1 /etc/hosts)
line2=$(echo $line | awk '{print $2}')
echo "$line $line2.localdomain" >> /etc/hosts
/etc/init.d/sendmail start
php-fpm

Be sure to specify a hostname inside your docker-compose.yml or when running the container, e.g.:

docker run -it --hostname foobar acme/php

or

docker-compose.yml

version: '2'
services:
  phpfpm:
    image: acme/php
    container_name: "my_php_fpm"
    hostname: "foobar"

Thats it - php mail() will work now. It's propably possible with alpine, too - but I did not manage to get that working yet. Feel free to enhance my solution ;)

@unoexperto

This comment has been minimized.

Copy link

commented Mar 27, 2018

I dunno guys. ssmtp didn't work for me out of the box. I get ssmtp: Cannot open mailhub:25 errors in the log. It seems like it ignores connection settings set by php code (MantisBT in my case).

@okainov

This comment has been minimized.

Copy link

commented Aug 19, 2018

Is there any update on it? Issue is still here...

@ukpasupport

This comment has been minimized.

Copy link

commented Aug 21, 2018

I am trying to search for a solution for this as the issue is still present

@WilliamDenniss

This comment has been minimized.

Copy link

commented Sep 29, 2018

Here's a simple way to enable PHP to send mail via a SMTP provider. Unless you want to manage your own sendmail service, and worry about the mail sending reputation of your host, etc, this is the way to go. You can replace the Sendgrid details in the example config with the SMTP provider of your choice (if you do, be sure to also update the port number, and note that some cloud providers block outbound port 25).

One caveat is that the script will block on the mail() call until the email has been accepted by the SMTP provider, it's not async out of the box.

Dockerfile

FROM php:5.6-apache

RUN apt-get update && \
   apt-get install -y ssmtp && \
   apt-get clean

# SSMTP settings
COPY ssmtp.conf /etc/ssmtp/ssmtp.conf
# PHP mail settings
RUN echo 'sendmail_path = "/usr/sbin/ssmtp -t -i"' > /usr/local/etc/php/conf.d/mail.ini

ssmtp.conf

# Sendgrid setup
# https://sendgrid.com/docs/for-developers/sending-email/ssmtp/
mailhub=smtp.sendgrid.net:587
AuthUser=<username>
AuthPass=<password>
UseSTARTTLS=YES
# Allow the "From" email header.
FromLineOverride=YES
@rmartinsjr

This comment has been minimized.

Copy link

commented Nov 20, 2018

Hi @WilliamDenniss! Thanks for sharing this solution. Tried myself after following your recipe and for me it's the neatest way to replicate sendmail function in containerized php applications.

@ooaklee

This comment has been minimized.

Copy link

commented Dec 10, 2018

Hey @WilliamDenniss, I used your solution with the official WordPress docker image, and it worked flawlessly. Thanks!

@Nimrod-666

This comment has been minimized.

Copy link

commented Jan 7, 2019

Hi there. I tried the ssmtp solution as you guys recommended and i got the issue that a testmail is sendable from my host system, but not inside the php:7.3-apache-stretch container.

Here are my configs (i replaced my domain with xxx):

#/etc/ssmtp/ssmtp.conf
root=noreply@xxx.de
mailhub=smtp.goneo.de:587
rewriteDomain=xxx.de
hostname=xxx.de
FromLineOverride=YES
AuthUser=noreply@xxx.de
AuthPass=xxx
UseTLS=YES

#/etc/ssmtp/revaliases
root:noreply@xxx.de:smtp.goneo.de:587
www-run:noreply@xxx.de:smtp.goneo.de:587

Now i try to send a testmail:

root@webserver:/var/www/html# echo "Subject: Test" | /usr/sbin/ssmtp -f noreply@xxx.de -vvv info@xxx.de
[<-] 220 smtp3.goneo.de ESMTP
[->] EHLO xxx.de
[<-] 250 DSN
[->] AUTH LOGIN
[<-] 334 VXNlcm5hbWU6
[->] bm9yZXBseUBibGFreWxsZS5kZQ0=
[<-] 535 5.7.8 Error: authentication failed: VXNlcm5hbWU6
ssmtp: Server didn't accept AUTH LOGIN (535 5.7.8 Error: authentication failed: VXNlcm5hbWU6)

As i already mentioned, it works flawless on the hostsystem with the same configfiles:

root@webdev:~# echo "Subject: Test" | /usr/sbin/ssmtp -f noreply@xxx.de -vvv info@xxx.de
[<-] 220 smtp1.goneo.de ESMTP
[->] EHLO xxx.de
[<-] 250 DSN
[->] STARTTLS
[<-] 220 2.0.0 Ready to start TLS
[->] EHLO xxx.de
[<-] 250 DSN
[->] AUTH LOGIN
[<-] 334 VXNlcm5hbWU6
[->] bm9yZXBseUBibGFreWxsZS5kZQ==
[<-] 334 UGFzc3dvcmQ6
[<-] 235 2.7.0 Authentication successful
[->] MAIL FROM:noreply@xxx.de
[<-] 250 2.1.0 Ok
[->] RCPT TO:info@xxx.de
[<-] 250 2.1.5 Ok
[->] DATA
[<-] 354 End data with .
[->] Received: by xxx.de (sSMTP sendmail emulation); Mon, 07 Jan 2019 18:56:22 +0100
[->] From: "root" noreply@xxx.de
[->] Date: Mon, 07 Jan 2019 18:56:22 +0100
[->] Subject: Test
[->]
[->] .
[<-] 250 2.0.0 Ok: queued as C202323F197
[->] QUIT
[<-] 221 2.0.0 Bye

The version of both ssmtps is 2.64. What's strange is, that it seems that the hostsystem begins with a STARTTLS handshake, and the container don't.

Has anybody a hint for me?

@WilliamDenniss

This comment has been minimized.

Copy link

commented Jan 11, 2019

@Nimrod-666 just a guess, but is the port correct in your config? My example used port 587 for sendgrid to avoid the issue of port 25 being blocked on GCP, but you may need to update that with the port number of the SMTP server you are using.

Note that some cloud providers block or throttle port 25, so you may need to use a different port if this affects you (as this can result in the container being able to send mail successfully locally, but then not when you deploy it to the cloud).

I've updated my original comment with that information.

@angeloreale

This comment has been minimized.

Copy link

commented Feb 17, 2019

Well here is my simple solution:

Dockerfile (for your custom php image)

FROM php:fpm
RUN apt-get update && apt-get install -y sendmail
ADD ./php.sh /opt/php.sh
ADD sendmail.ini /usr/local/etc/php/conf.d/
RUN chmod u+x /opt/php.sh
WORKDIR /opt
CMD ["php.sh"]

sendmail.ini

# Enable sendmail
sendmail_path = "/usr/sbin/sendmail -t -i"

php.sh

#! /bin/sh
line=$(head -n 1 /etc/hosts)
line2=$(echo $line | awk '{print $2}')
echo "$line $line2.localdomain" >> /etc/hosts
/etc/init.d/sendmail start
php-fpm

Be sure to specify a hostname inside your docker-compose.yml or when running the container, e.g.:

docker run -it --hostname foobar acme/php

or

docker-compose.yml

version: '2'
services:
  phpfpm:
    image: acme/php
    container_name: "my_php_fpm"
    hostname: "foobar"

Thats it - php mail() will work now. It's propably possible with alpine, too - but I did not manage to get that working yet. Feel free to enhance my solution ;)

I had to update this solution in order to make it work around here.

Added these lines to php.sh:

echo "$(hostname -i)\t$(hostname) $(hostname).localhost" >> /etc/hosts
echo "O HostsFile=/etc/hosts" >> /etc/mail/sendmail.cf

As well as defining an ENTRYPOINT in Dockerfile for php.sh:
ENTRYPOINT ["/opt/php.sh"]

@GrrrDog

This comment has been minimized.

Copy link

commented Mar 8, 2019

The previous configs didn't work for me due various reasons.
Came to the next solution:
Dockerfile

FROM php:apache
RUN apt-get update && \
  apt-get install -y exim4 &&\
  echo 'sendmail_path = "/usr/sbin/exim4 -t"' >> /usr/local/etc/php/conf.d/mail.ini && \
  echo 'SMTP = localhost' >> /usr/local/etc/php/conf.d/mail.ini && \
  echo 'smtp_port = 25' >> /usr/local/etc/php/conf.d/mail.ini 
COPY ./config/exim4.conf /etc/exim4/exim4.conf
RUN chmod 644 /etc/exim4/exim4.conf

exim4.conf

primary_hostname = anynameyouwant.io
hostlist legit_sending_hosts = 127.0.0.1 

local_interfaces = <; ::0 ; 0.0.0.0
ignore_bounce_errors_after = 2d
timeout_frozen_after = 7d
split_spool_directory = true
acl_smtp_rcpt = acl_check_rcpt
acl_smtp_data = acl_check_data

#                       ACL CONFIGURATION                            #
begin acl
acl_check_rcpt:
  accept  hosts = :
          control = dkim_disable_verify
  deny    message       = Restricted characters in address
          local_parts   = ^[./|] : ^.*[@%!] : ^.*/\\.\\./
  accept  hosts         = +legit_sending_hosts
          control       = submission
          control       = dkim_disable_verify
  accept  authenticated = *
          control       = submission
          control       = dkim_disable_verify
  deny    message       = "You are not allowed to send email"
acl_check_data:
  accept

#                      ROUTERS CONFIGURATION                         #
begin routers
dnslookup:
  driver = dnslookup
  transport = remote_smtp
  ignore_target_hosts = 0.0.0.0 : 127.0.0.0/8
  no_more

#                      TRANSPORTS CONFIGURATION                      #
begin transports
remote_smtp:
  driver = smtp

#                      RETRY CONFIGURATION                           #
begin retry
*                      *           F,2h,15m; G,16h,1h,1.5; F,4d,6h
#                   AUTHENTICATION CONFIGURATION                     #
begin authenticators

It's based on rickw/debian-exim-send
Hope it will help someone

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.