Search code examples
phpdocker

Setting up mail for PHP in a Docker container


I'm trying to get my PHP container to send emails. Both here and here it is mentioned that the configuration setting should be in the php.ini file.

However, when I put a phpinfo() somewhere in my code, this is what I see:

Configuration File (php.ini) Path           /usr/local/etc/php
Loaded Configuration File                   (none)
Scan this dir for additional .ini files     /usr/local/etc/php/conf.d
Additional .ini files parsed                /usr/local/etc/php/conf.d/docker-fpm.ini, /usr/local/etc/php/conf.d/docker-php-ext-exif.ini, /usr/local/etc/php/conf.d/docker-php-ext-gd.ini, /usr/local/etc/php/conf.d/docker-php-ext-gettext.ini, /usr/local/etc/php/conf.d/docker-php-ext-gmp.ini, /usr/local/etc/php/conf.d/docker-php-ext-intl.ini, /usr/local/etc/php/conf.d/docker-php-ext-memcached.ini, /usr/local/etc/php/conf.d/docker-php-ext-mysqli.ini, /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini, /usr/local/etc/php/conf.d/docker-php-ext-pdo_mysql.ini, /usr/local/etc/php/conf.d/docker-php-ext-sodium.ini, /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini, /usr/local/etc/php/conf.d/docker-php-ext-yaml.ini, /usr/local/etc/php/conf.d/docker-php-ext-zip.ini, /usr/local/etc/php/conf.d/newrelic.ini 

I'm running my PHP project inside a Docker container. Here's the Dockerfile (a bit simplified):

FROM composer:2 as vendor

COPY public/composer.json composer.json

RUN composer clearcache

RUN composer install \
    --ignore-platform-reqs \
    --no-interaction \
    --no-plugins \
    --no-scripts \
    --prefer-dist && \
    composer dumpautoload --optimize

FROM php:8.3-fpm-alpine3.19

EXPOSE 80

RUN pecl install xdebug && \
   docker-php-ext-enable xdebug

COPY config/docker-php-ext-xdebug.ini /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini

COPY public /var/www/repo/public

# install dependencies
COPY --from=vendor /app/vendor/ /var/www/repo/public/vendor/
RUN chown -R www-data /var/www/repo/public/vendor/

WORKDIR /var/www
CMD ["/var/www/repo/scripts/start"]

This is all fine, the container builds and the app runs fine (apart from the fact that it's not sending emails):

function _mail(
    string $to,
    string $subject,
    string $message,
    string $headers = '',
    string $params = ''
): void {
    if (!mail($to, $subject, $message, $headers, $params)) {
        throw new Exception('Something went wrong when sending email');
    }
}

When I run this, it always end up inside the if and throwing that exception, and I can't figure out why. The fact that PHP's mail() function is notoriously hard to debug doesn't help either (I've already read many SO questions about it, and I'm aware that using for example error_get_last() doesn't help).

As you can see, I am already adding an extra .ini file for my Xdebug config. Do I need to do something similar for the mail configuration? If so, how should that file be called and what should it contain?


Solution

  • The PHP mail() function works by calling out to a system binary with default parameters defined by the ini config sendmail_path - so usually /usr/sbin/sendmail -t -i - and passing the e-mail on stdin.

    You can set/change this in any php.ini that is loaded - which in your container is any *.ini file in /usr/local/etc/php/conf.d/. So you can just drop a new file there with your desired configuration like you already did for xdebug.


    But be aware that this then obviously also requires the configured binary to be installed within the container, i.e., sendmail. sendmail on the other hand must be properly configured to relay the passed e-mails to a mail transfer agent. It is usually installed together with an MTA like postfix to which it then delivers the mails locally. This would then mean you'd had to run an MTA in the container, too - which is most probably something you don't want.

    Instead you could rather use a sendmail alternative that can be configured to directly forward the e-mails to another server via SMTP, e.g., msmtp.


    This may sound needlessly complex - and it is. In the end it might be a better solution to use a proper mailing library for PHP which supports using SMTP servers directly - like the symfony/mailer.