phpsymfonymonologsymfony-mailer

How to define a service for mailer with a specific transport


I am using Monolog with HTML email formatter to send some alerts.

monolog:
    # ....
    symfony_mailer:
        type:           symfony_mailer
        from_email:     "%admin_email%"
        to_email:       "%admin_email%"
        subject:        "A problem occurred"
        level:          info
        content_type:   text/html
        formatter:      monolog.formatter.html

I want sending email with a specific email account defined as transport "monolog"

# config/packages/mailer.yaml
framework:
    mailer:
        transports:
            main: '%env(MAILER_DSN)%'
            monolog: '%env(MAILER_DSN_IMPORTANT)%'

For that, I can specify a service to use in the monolog config like mailer: 'monolog_mailer_transport' but I am not able to define the service to use the "monolog" transport.

service:
    # ....
    # NOT WORKING : HOW TO DEFINE THE SERVICE TO USE THE TRANSPORT 'MONOLOG' ?
    monolog_mailer_transport:
        class: Symfony\Component\Mailer\Transport\TransportInterface
        factory: ['@mailer.transports', 'get']
        arguments: ['monolog']

Solution

  • Unfortunately, at the moment, there's no out-of-the-box way to use a alternative transport for sending emails with logs. However, you can "hack" the system to achieve this. Here's how you can do it:

    First, define the transport service:

    monolog_transport:
        class: Symfony\Component\Mailer\Transport\TransportInterface
        factory: 'Symfony\Component\Mailer\Transport::fromDsn'
        arguments:
            - 'sendmail://default' // replace it to your ENV var
    

    Then, define the mailer service:

    monolog_mailer:
        class: Symfony\Component\Mailer\Mailer
        arguments:
            $transport: '@monolog_transport'
            $bus: null
    

    Important: We set $bus to null. If you don't do this, the email will be sent asynchronously, and you may lose the transport information, causing the wrong transport to be used. This is a bug, and there's a corresponding GitHub issue: https://github.com/symfony/symfony/issues/57871

    Configure Monolog to use the custom mailer:

    mail:
        type: symfony_mailer
        level: error  # Set the desired log level
        formatter: monolog.formatter.html  # Or any other format you need
        to_email: 'to@example.com'  # Replace with your email address
        from_email: 'no-reply@example.com'  # Sender's email
        subject: 'Symfony Application Error Logs'
        mailer: monolog_mailer // changed
    

    If disabling asynchronicity is not an option (and just a more clean way):

    In this case, you will need to create a custom service for Monolog that interacts with the mailer inside the service. This will allow you to manage the transport behavior directly from Monolog without the asynchronicity issue.

    Or you can try to change mailer to something else, like SwiftMailer, maybe it doesn't have this kind of bug.