Chapters
Scroll down to the script below, click on any sentence (including terminal blocks) to jump to that spot in the video!
Muy bien, ¡por fin ha llegado el momento de enviar correos electrónicos reales en producción!
Transportes de Mailer
Mailer viene con varias formas de enviar correos electrónicos, llamadas "transportes". Este smtp
es el que estamos utilizando para nuestras pruebas con Mailtrap. Podríamos configurar nuestro propio servidor SMTP para enviar correos... pero... eso es complejo, y tienes que hacer un montón de cosas para asegurarte de que tus correos no se marcan como spam. Boo.
transportes de terceros
Te recomiendo encarecidamente que utilices un servicio de correo electrónico de terceros. Éstos gestionan todas estas complejidades por ti y Mailer proporciona puentes a muchos de ellos para que la configuración sea pan comido.
Puente Mailtrap
Utilizamos Mailtrap para las pruebas, pero Mailtrap también tiene funciones de envío a producción ¡Fantástico! Incluso tiene un puente oficial
En tu terminal, instálalo con:
composer require symfony/mailtrap-mailer
Una vez instalado, comprueba tu IDE. En .env
, la receta añade algunos stubs de MAILER_DSN
. Podemos obtener los valores DSN reales de Mailtrap, pero antes tenemos que hacer algunos ajustes.
Dominio de envío
En Mailtrap, tenemos que configurar un "dominio de envío". Esto configura un dominio de tu propiedad para permitir que Mailtrap envíe correos electrónicos correctamente en su nombre.
Nuestros abogados aún están negociando la compra de universal-travel.com
, así que, por ahora, estoy utilizando un dominio personal que poseo: zenstruck.com
. Añade tu dominio aquí.
Una vez añadido, estarás en esta página de "Verificación del dominio". Esto es súper importante, pero Mailtrap lo hace fácil. Sólo tienes que seguir las instrucciones hasta que aparezca esta marca de verificación verde. Básicamente, tendrás que añadir un montón de registros DNS específicos a tu dominio. DKIM, que verifica los correos electrónicos enviados desde tu dominio, y SPF, que autoriza a Mailtrap a enviar correos electrónicos en nombre de tu dominio, son los más importantes. Mailtrap proporciona una gran documentación sobre ellos si quieres profundizar en cómo funcionan exactamente. Pero básicamente, le estamos diciendo al mundo que Mailtrap está autorizado a enviar correos electrónicos en nuestro nombre.
Producción MAILER_DSN
Una vez que tengas la marca de verificación verde, haz clic en "Integraciones" y luego en "Integrar" en la sección "Flujo de transacciones".
Ahora podemos decidir entre utilizar SMTP o API. Yo utilizaré la API, pero cualquiera de las dos funciona. Y ¡hey! Esto me resulta familiar: como con las pruebas de Mailtrap, elige PHP y luego Symfony. ¡Este es el MAILER_DSN
que necesitamos! Cópialo y salta a tu editor.
Se trata de una variable de entorno sensible, así que añádela a .env.local
para evitar confirmarla en git. Comenta el DSN de prueba de Mailtrap y pégalo a continuación. Eliminaré este comentario porque nos gusta mantener la vida ordenada.
¡Casi listo! Recuerda que sólo podemos enviar correos en producción desde el dominio que hemos configurado. En mi caso, zenstruck.com
. Abre config/services.yaml
y actualiza elglobal_from_email
a tu dominio.
¡Veamos si funciona! En tu aplicación, reserva un viaje. Esta vez utiliza una dirección de correo electrónico real. Pondré el nombre Kevin
y utilizaré mi correo electrónico personal:kevin@symfonycasts.com
. Por mucho que te quiera a ti y a los viajes espaciales, pon aquí tu propio correo electrónico para evitar enviarme spam. ¡Elige una fecha y reserva!
Estamos en la página de confirmación de la reserva, ¡es una buena señal! Ahora, comprueba tu correo electrónico personal. Yo voy al mío y espero... actualizo... ¡aquí está! Si hago clic, ¡esto es exactamente lo que esperamos! La imagen, el archivo adjunto, ¡todo está aquí!
A continuación, vamos a ver cómo podemos rastrear los correos electrónicos enviados con Mailtrap, ¡además de añadir etiquetas y metadatos para mejorar ese rastreo!
9 Comments
Hey @giorgiocba,
By "incoming" do you mean sending messages to a special email, parsing and sending to a webhook? Doesn't look like Mailtrap supports this.
for example, from a request form we have on our website
The typical pattern for this is: when the form is filled out, send an email to yourself with the form details (ie hello@mycompany.com). This would be a standard "outgoing" email.
Hope this helps,
Kevin


Hello SfCasts team!
Could you please advise why do I see 2 emails in the debug tool?
I have started with the initial configuration for the clean new SF project with --webapp option, which gave me the messenger, mailer and development smtp (webmail) components installed.
Then I have adjusted the SendEmailMessage to be transported via the sync transport.
Next, I have configured the MAILER_DSN to work with my SMTP service provider. After that I encountered the first problem: the real emails have not been delivered.
In the debug toolbar it was showing that there are 2 messages and 2 emails: The first e-mail was queued with [main] transport and second is sent with the local development smtp server. And no signs of the real DSN I have configured earlier. I thought it was the problem with my DSN string, but after some digging, I decided to disable webmail stuff at compose.override.yaml. That helped. Finally, I saw again 2 emails, but second email is sent via the proper smtp transport and the email has hit my mailbox. But still it is not clear why there were 2 emails and 2 messages in the debug toolbar?
Finally I have set the framework.mailer.message_bus option to false. Now all works just fine, but I am wondering if the described is a normal behaviour or it was some misconfiguration, or something else?
Hey @Maxim-M,
For the MAILER_DSN
problem: as I think you've figured out, when using Symfony CLI + Docker, the MAILER_DSN
is intercepted and changed to point to the mailer
container.
The double emails but only when using messenger... this one has me stumped. This is not normal behaviour and could be a misconfiguration but can't figure out what that could be. Question: is the Message-ID
header of the two emails the same?
Let's try and figure this out!
Kevin


Hey Kevin,
No, the Message-ID
is different.
I have just tried one more thing - switched the transport back to async
and, surprise! One e-mail is queued, and delivered after message consumption. I did not try this at the beginning, as there is no need in asynchronous delivery during development, so I just switched the routing to sync: 'sync://'
.
Seems like the issue is localized to synchronous transport.
Any idea where could we dig further?
Ok, I think I've replicated what your seeing. Here's a summary of what I'm seeing when SendEmailMessage
is routed to sync
:
- In profiler, 2 emails shown as sent:
- 1 to
[main]
transport - 1 to configured
MAILER_DSN
transport - Both of these have different
Message-ID
headers
- 1 to
- In profiler, 2
SendEmailMessage
shown as dispatched - Only 1 email actually sent to the configured
MAILER_DSN
but has a differentMessage-ID
from the two emails shown in the profiler...
The fact that only 1 email is actually being sent leads me to believe this is purely a profiler issue but, can you confirm this is also the case for you (despite what the profiler says, only a single email is actually being sent)?
--Kevin
I found this issue, which talks about the same thing we found. The conclusion seemed to be this is behaving correctly but still, it's a bit confusing until you understand why.


Yes, only the one e-mail is being sent.
As for the explanation on the GitHub... It could be the reason. Here is my guess: in case of the sync
transport, the profiler takes the snapshot of the request, during which the message is queued and instantly consumed, which leads to e-mail sending, also being logged. Thus we see 2 e-mails logged: first for the queuing and second for sending. And this explains why for the async
transport we see just one email and message. By the request finish time there is log for only the queued e-mail. However, it is not very clear why the e-mails have different Message-ID
. I can only guess it is due to serialize / deserialize process. And why it shows 2 messages? I think, profiler could be more clear :)
Thank you very much for your help!
No problem, I'm happy we figured this out!

"Houston: no signs of life"
Start the conversation!
What PHP libraries does this tutorial use?
// composer.json
{
"require": {
"php": ">=8.2",
"ext-ctype": "*",
"ext-iconv": "*",
"doctrine/dbal": "^3", // 3.9.4
"doctrine/doctrine-bundle": "^2.13", // 2.13.2
"doctrine/doctrine-fixtures-bundle": "^3.6", // 3.7.1
"doctrine/orm": "^3.3", // 3.3.1
"dragonmantank/cron-expression": "^3.4", // v3.4.0
"knplabs/knp-time-bundle": "^2.4", // v2.4.0
"league/html-to-markdown": "^5.1", // 5.1.1
"symfony/asset": "7.2.*", // v7.2.0
"symfony/asset-mapper": "7.2.*", // v7.2.0
"symfony/console": "7.2.*", // v7.2.1
"symfony/doctrine-messenger": "7.2.*", // v7.2.3
"symfony/dotenv": "7.2.*", // v7.2.0
"symfony/flex": "^2", // v2.4.7
"symfony/form": "7.2.*", // v7.2.0
"symfony/framework-bundle": "7.2.*", // v7.2.2
"symfony/mailer": "7.2.*", // v7.2.0
"symfony/mailtrap-mailer": "7.2.*", // v7.2.0
"symfony/messenger": "7.2.*", // v7.2.3
"symfony/monolog-bundle": "^3.10", // v3.10.0
"symfony/remote-event": "7.2.*", // v7.2.0
"symfony/runtime": "7.2.*", // v7.2.0
"symfony/scheduler": "7.2.*", // v7.2.3
"symfony/security-csrf": "7.2.*", // v7.2.2
"symfony/stimulus-bundle": "^2.21", // v2.22.1
"symfony/twig-bundle": "7.2.*", // v7.2.0
"symfony/validator": "7.2.*", // v7.2.2
"symfony/webhook": "7.2.*", // v7.2.0
"symfony/yaml": "7.2.*", // v7.2.0
"symfonycasts/tailwind-bundle": "^0.7.1", // v0.7.1
"twig/cssinliner-extra": "^3.18", // v3.18.0
"twig/extra-bundle": "^3.0", // v3.18.0
"twig/inky-extra": "^3.19", // v3.19.0
"twig/twig": "^3.0", // v3.18.0
"zenstruck/messenger-monitor-bundle": "^0.5.1" // v0.5.1
},
"require-dev": {
"phpunit/phpunit": "^9.5", // 9.6.22
"symfony/browser-kit": "7.2.*", // v7.2.0
"symfony/css-selector": "7.2.*", // v7.2.0
"symfony/debug-bundle": "7.2.*", // v7.2.0
"symfony/maker-bundle": "^1.61", // v1.62.1
"symfony/phpunit-bridge": "^7.1", // v7.2.0
"symfony/stopwatch": "7.2.*", // v7.2.2
"symfony/web-profiler-bundle": "7.2.*", // v7.2.2
"zenstruck/browser": "^1.9", // v1.9.1
"zenstruck/console-test": "^1.7", // v1.7.0
"zenstruck/foundry": "^2.2", // v2.3.0
"zenstruck/mailer-test": "^1.4" // v1.4.2
}
}
Hello. We're using Mailtrap as a tool for outgoing email, but I'm not sure what happens with incoming email. Can Mailtrap also be used to handle incoming email, for example, from a request form we have on our website?