Problem/Motivation
Drupal core mail capabilities are stuck in the early 2000.
Steps to reproduce
Attempt to use mailhog (in development) or SMTP (in production).
Proposed resolution
As per symfony docs:
Symfony's Mailer & Mime components form a powerful system for creating and sending emails - complete with support for multipart messages, Twig integration, CSS inlining, file attachments and a lot more. Get them installed with:
Emails are delivered via a "transport". Out of the box, you can deliver emails over SMTP. Instead of using your own SMTP server or sendmail binary, you can send emails via a third-party provider.
Symfony mailer is maintained in the symfony framework repository. Like all symfony components it is available as a separate package as well.
As a pre-requisite of #1803948: [META] Adopt the symfony mailer component, add the symfony/mailer component as a composer dependency to Drupal core. Additionally make all supported symfony mailer transports accessible via a simple mail plugin which can act as a drop-in replacement for the existing php mail plugin.
Behavioral changes compared to PHP mailer plugin
The Symfony mime component doesn't support format=flowed soft wrapped text. Thus, mails sent with the Symfony mailer plugin may look slightly different in MUAs supporting soft wrapping compared to the ones sent with the default PHP mail plugin.
The Symfony mailer plugin from this MR addresses #3174760: Mails resembling HTML are corrupted. Markup generated by custom or contrib modules might be rendered with visible HTML tags if they are using plain strings instead of MarkupInterface.
By default, the symfony mailer plugin uses sendmail://default as the transport DSN. I.e., it attempts to use /usr/sbin/sendmail -bs in order to submit a message to the MTA. Sites hosted on operating systems without a working MTA (e.g., Windows) should configure an alternative DSN (e.g., SMTP, see below).
Manual testing instructions
With this patch in place (and composer dependencies installed), use the following drush command to switch the mail plugin:
drush config:set system.mail interface.default symfony_mailer
In order to configure the DSN, use the following command:
- For the default sendmail transport:
drush config:set system.mail mailer_dsn sendmail://default - For mailhog on localhost:
drush config:set system.mail mailer_dsn smtp://localhost:1025 - For authenticated SMTP:
drush config:set system.mail mailer_dsn smtp://user:pass@smtp.example.com:25
Security considerations
The mailer_dsn key in system.mail config stores the symfony mailer data source name. This is used to select the mailer transport. Examples of valid DSN include null://null, smtp://user:pass@smtp.example.com:25 or sendmail://default. Many DSN also take additional options in form of URL query parameters.
The sendmail transport optionally takes a command option used to specify the path to the sendmail binary. Accounts with write access to the mailer_dsn key in system.mail may use this option to execute any binary on the host accessible by the web server process.
There is a proposal to fix this in a follow-on issue #3384844: [PP-1] Add security checking for Symfony Mailer transports. That would be after (or as part of) #3379794: Add symfony mailer transports to Dependency Injection Container (mail delivery layer) which is postponed on this.
Impact on contrib
The contrib Drupal Symfony Mailer module declares a dependency on the symfony mailer component as well. Version requirements over there currently are symfony/mailer": "^5.3 || ^6.0. Sites currently having this module enabled might unexpectedly upgrade to a different version of the symfony mailer component when upgrading to a Drupal version including this MR.
Remaining tasks
Raise a follow-on issue to factor out the transport service.
User interface changes
None.
API changes
None.
Data model changes
Add new config key mailer_dsn in system.mail.
Release notes snippet
| Comment | File | Size | Author |
|---|---|---|---|
| #91 | 3165762-nr-bot.txt | 90 bytes | needs-review-queue-bot |
| #87 | 3165762-nr-bot.txt | 90 bytes | needs-review-queue-bot |
| #78 | 3165762-nr-bot.txt | 90 bytes | needs-review-queue-bot |
| #41 | mailsystem-screenshot.png | 51.46 KB | znerol |
| #34 | 3165762-nr-bot.txt | 90 bytes | needs-review-queue-bot |
Issue fork drupal-3165762
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
jungleComment #3
berdirThere are already existing issues for html2text, I'm not sure about mixing the two.
The question is if we add html2text, what do we do with our own html 2 text code. It would allow us to replace a massive, ugly, untested chunk of code in core. But there is no standard for this transformation afaik, so the result of the library is completely different. see #2830384: Deprecate MailFormatHelper in favor of html2text/html2text library. So we need to figure out if the exact structure of the result is an API (and we need a BC setting or something) or if we can just switch it out.
Comment #4
berdirAnd yes, we should use the symfony mailer component, which is stable since symfony 4.4: https://symfony.com/doc/4.4/mailer.html
Comment #5
berdirAnd we should reach out the the current swiftmailer module maintainer to come up with a plan and what exactly would be in core. Because the module mostly does quite a lot of HTML mail related processing that we'll likely not be able to bring into core entirely.
Comment #6
jungleThanks @Berdir! +1 to use the symfony mailer component, let's postpone this.
Comment #7
junglePostpone on #1803948: [META] Adopt the symfony mailer component
Comment #10
berdirHere's a proof of concept. I'm sure I didn't properly add the mailer component as a dependency ;)
I'm using the new native transport factory, that will automatically use sendmail or smtp configuration, so that should also work on windows.
I was able to send a mail locally with mailhog sendmail wrapper configured in php.ini. Only problem was that symfony checks that you pass in -t and I hadn't configured it like that in php.ini.
This could be a first step, and a follow-up could then add a similar transport configuration settings UI that swiftmailer.module currently provides.
AFAICS, changing the html2text implementation could be a completely separate issue, as well as supporting HTML mails. The goal of this would be to just switch the transport with similar behavior as we have now (it's not the same though, it does not use mail() but sendmail directly).
Obviously the mailer and transport should be services, this is just a quick & dirty proof of concept.
Comment #11
berdirI wasn't sure if any of this is necessary, possibly we can just drop it, making this even simpler.
One thing to check would be the Return-Path header. I saw that I ended up with two return-path e-mails.
Comment #12
berdirOne interesting thing on replacing hook_mail is that right now, drupal core doesn't care about HTML, but you _can_ alter the mail and make it a nice HTML mail with swiftmailer for example. When we move to directly creating Email objects as the API, then we lose that ability as the Email object has explicit text() and html() methods. It's designed for a different use case where the application/you decide what kind of mail you want to send and there is no need to alter.
We could keep MailManager and add a method like send(Email $email, array $context) or whatever, that would invoke an event that would still alllow you to customize mails sent by other modules. And that's a problem for several steps/issues further down the line.
Comment #13
imclean commented@Berdir #11,
The Return-Path header is added by the final delivery agent and set to the envelope sender email address (SMTP
MAIL FROMcommand). Drupal also adds the Return-Path header directly, presumably in an attempt to ensure delivery on some mail systems, however this isn't correct and is in violation of the RFC. See: https://datatracker.ietf.org/doc/html/rfc5321#section-4.4I've seen duplicate Return-Path headers with plain Drupal, SMTP auth module and SwiftMailer.
With the change of the mail system, this might be a good time to look at how Drupal handles this header. See #3055296: Setting the "Return-Path" header doesn't follow RFC 5321
Comment #14
adamps commentedHere is a new contrib module Symfony Mailer that prototypes a more ambitious approach that could eventually be adopted into Drupal Core.
It defines an entirely new mail interface that would allow native Drupal Core support for advanced features including HTML mails, templating, theming with inline CSS, file attachments and more. There could be a back-compatibility shim (not yet written).
Comments welcome😃.
Comment #17
cilefen commentedComment #18
chris matthews commentedComment #19
catchThis isn't really postponed on anything afaik.
Comment #20
longwave#10 no longer applies, NW for that and the issue summary update.
Comment #21
adamps commentedThe patch in this issue has the advantage of being very simple, but also it doesn't yet add much advantage. It would technically use symfony/mailer, but it would bypass most of the features - for example the headers are pre-built then added as UnstructuredHeader. It would not support HTML email. It would retain some bugs and oddities in MailManager and PhpMail. There are no configuration options, and the transport is hard-coded as NativeMailer (which BTW is documented as Not recommended, prefer Sendmail).
The Symfony Mailer module does a lot more. It could eventually be integrated in part into Core. I feel it would be valuable to have a discussion on the direction for Core to move forward, probably in the parent META issue.
Comment #25
znerol commentedReroll of #10 and switch to MR workflow, still needs work.
Comment #26
znerol commentedComment #27
znerol commentedAdded mailer and transport to core services. I suggest to make the mailer a
lazyservice.Tentatively marking
mailer.transportas non-public. Also addedmail_dsnkey insystem.siteconfig. This is used by the mailer transport factory to construct any transport supported by symfony mailer out of the box. Modules providing even more specialized transports might want to replace the factory and the mailer transport service.Use the following commands to enable the mail plugin (and change the transport to mailhog):
(n.b. drush doesn't seem to work for me right now with the 11.x branch, use config export / import web interface if that problem persists...)
Seeking feedback on the service layout and the config now. Leaving state at needs work. As pointed out by @AdamPS the code in the plugin definitely needs some more love.
Comment #28
znerol commentedApplied the fix from #3226117: Uncaught RfcComplianceException when email From name contains a comma and cleaned up the plugin code a bit. Still needs work (plugin test similar to PhpMailTest).
Comment #29
znerol commentedRemoved the
lazyflag. Will try to readd it after the other pieces are in place.Comment #30
znerol commentedSo, took a step back on this and reduced the changes a bit: I feel that we shouldn't expose the mailer component as part of the initial patch in the service container. Doing so has some tricky consequences. From this point in time, the mailer service is (official) API and even more important the MessageEvent is as well.
MessageEventwill be a perfect candidate to eventually replacehook_mailandhook_mail_alter. However, I'd like to avoid mixing call paths from the old API (hooks acting on mail arrays) and the new API (event subscribers acting on subclasses of Email).The Symfony Mailer component will bring many benefits to Drupal core over time. But let's concentrate on tackling those issues one by one.
The minimalistic mail plugin in the current PR can be used as a drop-in replacement for php mail. With the additional benefit that we can start using any transport supported by Symfony Mailer.
Let's get that in rather sooner than later. Needs review.
Comment #31
smustgrave commentedIssue summary still needs to be updated I believe.
with the change to the schema possible we made need an upgrade path also.
Comment #32
znerol commentedComment #33
znerol commentedComment #34
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".
This does not mean that the patch needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #35
znerol commentedRebased
Comment #36
adamps commentedGreat the new code seems much better, thanks.
1)
I feel that would be a mistake. Supporting HTML is a simple change to make now - it would hardly even increase the code complexity at all. It seems desirable for the vast majority of sites who take the trouble to enable a non-standard plug-in. Why not do it from the start?? Changing from plain text emails to HTML would be a disruptive (non-BC) change.
2) On the other hand, from my experience developing Drupal Symfony Mailer, I would say that writing the code for transports is complex and I can see various potential problems with the current code. IMO this is the part that we should tackle in a follow-up. If the consensus of opinion doesn't agree then I could post my comments here.
3) These comments apparently haven't been addressed.
4)
str_getcsv()is an improvement but it still seems rather too simplistic. Compareswiftmailer_parse_mailboxes(), which even itself has had some recent problems. Using a proper external maintained library seems even better.Comment #37
znerol commentedNo. Adding features is not considered a BC-break.
Tagging for framework manager review, especially concerning approach and scope. Hope to get that unblocked with some consideration from a core maintainer.
Comment #38
longwaveI am excited to finally see the mail system improving. I think that small incremental improvements are the way to go though I am still concerned about how we provide BC and how contrib/custom modules will be able to integrate with a new mail system while still supporting the old one.
One question regarding the config, shouldn't the DSN be stored in
system.mailinstead ofsystem.site?Comment #39
adamps commentedTrue we can add a new feature with a config option to enable it. However if we change the default behaviour that's a BC-break. The current patch has default plain text, whereas I imagine most people want HTML - this might become difficult to change later.
Furthermore the patch copies the bug in
PhpMail#3174760: Mails resembling HTML are corrupted which seems unlikely to be fixed because it would be a BC-break. Here is what @catch said on that issue:I started Drupal Symfony Mailer project to address some limitations of the existing Drupal Core mail system, and of Swiftmailer (which I am also a maintainer for). Here we have a golden opportunity to get things right, yet there seems to be a strange insistence on this issue to make the new code worse than those contrib modules, ignoring the lessons learnt there.
Anyway I've made my points, and I'm not going to keep repeating them. If needs be I can continue to use and maintain Drupal Symfony Mailer so whatever happens here it's not a problem for me.
Comment #40
berdirLeft some comments on the MR.
Clear +1 on not changing anything in regards to HTML mails here. It really is not simple. HTML mails need a wrapper HTML template which I'm sure would come with endless bikeshedding, it needs tests, and you need ways for the opposite of what this does, meaning converting non-HTML mail content to HTML which has security aspects, it would change how mails look on existing sites and so on.
This is _not_ introducing a new mail API, it's a drop-in replacement with the existing mail API that just uses a more modern API internally. That it's behavior is as close as possible to PhpMail is a good thing, as it allows sites that are not using swiftmailer/symfony_mailer modules to switch. The goal of this is issue is not to replace either of those modules. We're many steps away from that. If anything, what we can realistically replace is modules like smtp with a bit of UI, that could live in mailsystem.module for now until core exposes that setting.
Once this first step is done, then we can look into opt-in support of HTML mails through the existing system but it IMHO probably makes more sense to design a new Mail API that bypasses the current hook system entirely.
Comment #41
znerol commentedMarked the plugin as experimental in the
labelplugin property. This will show up in the contrib Mail System configuration.The Drupal Symfony Mailer integration module doesn't provide a
@Mailplugin but instead replacesplugin.manager.mailentirely. Thus, when Drupal Symfony Mailer module is enabled,@Mailplugins do not have any effect at all. That makes things easier for core, since there is no need to further specify whether the plugin in the current MR is from core or from contrib.Comment #42
znerol commentedComment #43
znerol commentedTook a closer look at the header issue brought up by @AdamPS after #26:
Symfony Mailer requires control over
Content-TypeandContent-Transfer-Encodingheaders. Regrettably it lacks support for soft wrapped text (format=flowed). Thus I had to remove the call toMailFormatHelper::wrapMail().Comment #44
znerol commentedComment #45
znerol commentedAdding issue credits for @AdamPS for insightful comments.
Comment #46
smustgrave commentedWith the new service and new composer dependency think it could use a change record.
Don't mind marking that after and putting in committer queue.
Comment #47
znerol commentedCR draft.
Comment #48
adamps commentedGreat many thanks @znerol for the great work. Please I hope you can accept my apologies for the tone of my earlier comments - I get myself so fixed on a single idea sometimes that I can't see any other options.
@Berdir thanks for explaining why we don't want to do HTML email here.
Here is my summary of things we could still consider.
1) I now understand that we want a drop-in replacement for PhpMail - but do we definitely want to copy it's bug #3174760: Mails resembling HTML are corrupted? Once we have released this new mail plugin, there is a BC impact to change later. Swiftmailer and Drupal Symfony Mailer have both fixed this bug. The linked issue has a simple patch that we could take. @catch marked the linked issue as postponed on this one, suggesting it be fixed here.
2) Transport DSNs have security implications. With
sendmailtransport you can pass thecommandparameter to run any system command. Of course the risk all depends on who has access to control the DSN, however it seems that someone is likely to write a GUI to expose it in contrib/custom software. In Drupal Symfony Mailer we protected against this using a variable in settings.php. It would be great if the core and contrib variants could agree on a common security mechanism (could be a follow-up issue).3) The code as it stands doesn't allow for custom mailer transports beyond the ones hard-coded into the
Transportclass. In Drupal Symfony Mailer we created a way to allow that. Again it would be great if the core and contrib variants could agree on the mechanism (could be a follow-up issue).4) Drupal Symfony Mailer includes a detailed GUI for configuring transport DSN, with form plug-ins for each of the different underlying transports. What we found is that the natural structure for storing DSN configuration is to use a separate field for each of the component parameters (see below). We also ended up with the possibility for multiple configured transports, which could be used for loadbalancing/failover or for different email types. This suggests that in the end we would need more than a single
mailer_dsnconfig setting. OK so how does this all affect us now? Maybe not at all. Maybe we could after all call the parametermailer_default_dsnand create a hook to alter it (the hook could be a follow-up issue). Maybe something else???Comment #49
znerol commentedNo worries, @AdamPS you are doing fantastic work in contrib and in the core issue queue.
The goal of this issue is to keep the cost of switching away from PHP mail plugin to Symfony mailer transports to zero for most sites. The Symfony mailer mail plugin is not new API but just provides access to Symfony mailer transports to code using the legacy API.
That said, I think it is sensible to fix the plain text conversion here. We already ditched the soft wrapping anyway.
Good to know. Definitely needs to be considered when a configuration UI is built (no matter whether this happens in core or contrib).
Correct. The transports available from Symfony will cover the requirements of most sites. More exotic use can be solved in contrib or custom modules. For the moment by supplying their own mail plugin. Later by overriding the transport service (see below).
I guess many people would appreciate a plugin based way to configure the DSN.
A glimpse of how the services structure could look like when the new API is introduced in a follow-up is shown in commit 0da26475. With this structure, the only thing contrib or custom code needs to do in order to customize the transport is to replace the
mailer.transportservice.Note that Symfony provides wrapper transports for round-robin and fail-over scenarios. Something similar could be done in a contrib / custom module to redirect mails to one or the other actual transport depending on their origin, type or destination.
I very much hope it is enough if core provides only one transport (service) configured by only one DSN. More complicated use cases are better left to contrib and custom modules.
Comment #50
adamps commentedThanks @znerol
Actions
mailer_dsnto say that any special characters within passwords and keys must be URL encoded. See #3279696: For DSN transport, document to escape special characters in keys/passwords.Discussion
So we share the vision of extensibility, with different possible ways forward.
Yes indeed, and we can use them with the patch in this issue using a special syntax in the transport dsn - it doesn't even need custom or contrib code.
O, but I guess what we want to avoid is multiple contrib modules overriding the transport service, because then it's only possible to install one of them. Instead we'd like a single contrib override of the transport service (somewhat like mailsystem module) that provides a plug-in architecture for other modules to add a mailer transport back-end or GUI.
Drupal Symfony Mailer provides an excellent starting point for this, and I think it would be feasible to refactor the code into a separate module or sub-module that can be used for either with the core mail plug-in or with Drupal Symfony Mailer itself. This is a reasonably well-contained and small piece of code and in the longer term, I feel it would be advantageous to introduce it into core - however we can see😃.
OK, but putting the security mechanism in the GUI layer is potentially risky as then badly written contrib/custom code can bypass it and introduce security issues. It feels much better to put the security into the core, i.e. into the above overridden transport service.
Comment #51
berdirIt is a Plugin, if anyone wants to do something fancy it's easy to subclass and overwrite the method. That can be a separate Plugin and mailsystem and even core provides mechanisms to use specific ones for specific cases. Please lets keep this simple. we can define entirely different mechanisms and configurations for a new mail API key without BC concerns.
Security concerns will need sign off from core maintainers and maybe the security Team. we can maybe leverage config validation API, but if it's protected by a restricted permission then being able to set an insecure value is not a security issue.
Comment #52
znerol commentedAdded a security considerations section to the issue summary. Requesting a review by a security team member in order to decide whether or not paths to binaries are acceptable in config.
Comment #53
adamps commentedThanks for the replies. @Berdir NB everything in the "discussion" part has no effect on this patch, and I have no BC concerns here. All I was saying is that:
In both cases for the solution you would currently have to create a sub-classed mail plug-in (or override the upcoming mailer transport service). This seems inelegant, and creates problems with multiple modules clashing, e.g. module A creates transport override with smtp GUI, module B creates transport override with sendmail GUI, and a site wants failover between the two.
I suggested code that mostly already exists in Drupal Symfony Mailer can solve both problems (creating plug-ins for transport GUI), allowing commonality between the core and contrib integrations of Symfony Mailer. If you believe this doesn't belong in core, sure. Or are actually recommending that it isn't necessary even in contrib?
Comment #54
adamps commentedI spotted one more thing:
Drupal Symfony Mailer requires
"symfony/mailer": "^5.3 || ^6.0"Core recommended requires
"symfony/mailer": "v6.3.0"So this patch would force sites using core recommended and symfony/mailer v5.x to a major upgrade of symfony/mailer. This should presumably be documented in the release note, and we should likely introduce this patch in a minor release rather than a patch release.
Comment #55
znerol commentedComment #56
znerol commentedDocumented this in the issue summary. I'd like to delegate the decision about target releases to the people who are actually responsible for that part (i.e., core committers). Note that contrib modules may specify core compatibility using the
core_version_requirementkey in theirinfo.ymlfile. Thus, a contrib module may provide different versions in order to ensure compatibility with various core versions.Comment #57
znerol commentedComment #58
berdir> creates problems with multiple modules clashing, e.g. module A creates transport override with smtp GUI, module B creates transport override with sendmail GUI, and a site wants failover between the two.
If modules override the method to initialize the transport, they can also use a different setting, so two different plugins shouldn't clash then. And sure, it's not that elegant, but it's already way more elegant than what a module like smtp has to do now and a step forward.
> I suggested code that mostly already exists in Drupal Symfony Mailer can solve both problems (creating plug-ins for transport GUI), allowing commonality between the core and contrib integrations of Symfony Mailer. If you believe this doesn't belong in core, sure. Or are actually recommending that it isn't necessary even in contrib?
All I'm saying is that it doesn't belong in this issue, which we agree on I think. I haven't reviewed the specific implementation in symfony_mailer, but I agree that it makes sense to have an extensible system to configure the transport later, the hardcoded settings in swiftmailer always bugged me ;) I guess that will be one aspect of the replacement of the current mail API in core. Happy to discuss in later issues how much of that should be in core and how much in contrib. Similar to now, core could provide the plugin type with very basic options and a UI for SMTP and other configurations could be in contrib.
I'd like to go back to one earlier topic, native vs sendmail, per #21:
> the transport is hard-coded as NativeMailer (which BTW is documented as Not recommended, prefer Sendmail).
Yes, that is documented here: https://symfony.com/doc/current/mailer.html#using-built-in-transports and it says that, but it also says "if possible". I'm unsure if we can do that. My understanding is that sending mails would then not work on Windows without manually installing sendmail. I think now that works out of the box, so this might be a deal-breaker, maybe only once this is a stable/default replacement, maybe already now, I really don't know, that's not a decision that I can make, but I think it's one that needs to happen. Finding people who can test on Windows (not WSL2, actual native windows) is always very hard. A possible way forward might be to just document that in the change record (and a documentation page that we need to pass the documentation gate I think) and have a follow-up to discuss that further and see if anyone complains? ;)
> So this patch would force sites using core recommended and symfony/mailer v5.x to a major upgrade of symfony/mailer. This should presumably be documented in the release note, and we should likely introduce this patch in a minor release rather than a patch release.
Drupal 10 requires Symfony 6, so it makes sense to me to only allow that version like all other Symfony dependencies. Anyone on D10 is likely already using the 6.x version. But sure, doesn't hurt to specify that core requires symfony/mailer 6 in the change record. And recommended can always only require one specific version, that's exactly what core-recommended exists for.
Comment #59
znerol commentedTook a look at the mechanism how transports are constructed with the
nativescheme:NativeTransportFactory follows this logic:
sendmail_pathini is set, then aSendmailTransportis instantiated with that command.SmtpTransportwith the values fromsmtpandsmtp_portini settings.This logic is all sane. The problematic thing is that Symfony mailer prefers
/usr/sbin/sendmail -bsand PHP defaults to/usr/sbin/sendmail -t -i.Comment #60
adamps commentedThanks @Berdir. I feel it would be great to have a small group of experts to advise on overall strategy for Drupal Symfony Mailer in contrib. As function is added to Core then Contrib should adapt, so that it can continue to be used and fill in the gaps that Core chooses not to include.
As a reminder, Symfony docs has this warning message:
Perhaps we could use Native only on Windows??
Comment #61
adamps commentedIn my testing of splitting addresses,
str_getcsv()is an improvement onexplode()however it's not 100%:- it works if the display name contains a comma
- if fails if the display name contains a less-than (because it removes the quotes within each address)
However I guess it's the same as already done elsewhere in Core.
Comment #62
znerol commentedThe Symfony Mailer Framework Bundle is setting up transports like this:
The
$configvariable is an array of container parameters with all subkeys of themailerkey. In absence of any configuration, a symfony based application defaults tosmtp://null.I think we should follow that example. SMTP on localhost works out of the box in many production environments. For development, people tend to lean towards something docker based (e.g., ddev which is capable of injecting the necessary mailhog settings already).
Comment #63
znerol commentedComment #64
znerol commentedRegrettably
smtp://nulldoesn't work at all (fails withSymfony\Component\Mailer\Exception\TransportException: Connection could not be established with host "ssl://null:465": stream_socket_client(): php_network_getaddresses: getaddrinfo for null failed: Name or service not known).Also
smtp://localhost:25doesn't work neither reliably with a local postfix. The problem here is that it tries to useSTARTLSand fails to verify the certificateCN(Symfony\Component\Mailer\Exception\TransportException: Unable to connect with STARTTLS: stream_socket_enable_crypto(): Peer certificate CN=`<my-hostname->' did not match expected CN=`localhost'). Thus, back tosendmail://default.In that case I prefer to instruct windows users to specify the SMTP DSN directly in
system.mailmailer_dsn.Comment #65
znerol commentedComment #66
imclean commented@znerol,
This can happen if the SMTP server responds that it supports STARTTLS but only has a self-signed certificate. Symfony Mailer (and other mail libraries) usually default to using STARTTLS if the server supports it.
There are a few ways around it.
smtp://localhost:25?verify_peer=0Comment #67
longwaveI don't think we should try changing the default transport here; if this is a near drop-in replacement for the PHP mail plugin then by default it should function as close to the original as it can.
Regarding Windows we are intending to drop official support for Windows in production, because as far as we can determine, there are very few users running Drupal on IIS/Windows, and we get very little help with Windows-related issues in this queue: #3358248: [policy, no patch] Drop support for IIS in Drupal 11
Comment #68
znerol commentedSure, the correct way is obviously to run a mailserver with a proper certificate.
I tested this on a rather fresh Debian. Postfix runs with a self-signed TLS cert by default when installed from packages. That will be the case on many hosts. Hence, lots of people will run into that problem if Drupal ships with the DSN set to
smtp://localhost:25.I'd prefer Drupal to use a default transport which doesn't require people to mess with their MTA config.
Comment #69
imclean commentedMakes sense. Would disabling verify peer by default be a problem? Even if it was only applied to localhost.
Comment #70
znerol commentedYes. I feel that core shouldn't be disabling security settings in its defaults. I can only speak for myself, but I often look through core code for best practice if I'm unsure how to solve a particular problem in a contrib or a custom extension. If core promotes
verify_peer=false, then silly people like me might start thinking that this is good thing.Also
sendmail://defaultis more likely to behave similar to the PHPmail()function on *nix platforms. Which is inline with the direction suggested by @longwave in #67.Comment #71
longwaveBefore 2016 Drupal did not verify peers on SSL connections, and this was fixed in #1081192: Verify peer on HTTPS if cURL available (but be careful of built-in cert bundles in the codebase). I don't think we should undo some of that here; SMTP is a bit different but as stated in #70 core should be demonstrating best practices and not provide insecure defaults.
Comment #72
berdirI know I brought the topic up, but IMHO it's fine to default to sendmail for this initial/experimental/non-default mail plugin, if people who use this need to manually change configuration then I guess we can also expect them to read about windows and other special cases where the default doesn't work.
I think we do need a proper documentation page/section for this, not just the change record though.
It's a bit different when it will be the default option, but I think we can discuss that in a follow-up that blocks making it non-experimental and mention that in the meta.
@longwave: I think one bit where we need committer feedback is whether it's OK to have an experimental plugin in core just as-is, or if we need to put it in an experimental module.
Comment #73
longwaveDiscussed the experimental plugin with @catch. We agreed that as it is not visible via UI (except with mailsystem installed), then it is OK to add an experimental plugin directly to core as long as we also mark it @internal for now.
An experimental module would mean later having to merge that into core, and also it would add a plugin that does nothing on its own as there is no UI to configure it yet, so it could be somewhat confusing to users.
@Berdir also asked about a dependency evaluation.
symfony/maileris part of Symfony which we already heavily depend on, and which shares the same maintainers, security policies and release cycle. There is some overlap with the existing PHP mailer plugin but the whole point of this issue is to eventually replace our plugin with an improved one. We do not have individual listings of Symfony components on https://www.drupal.org/about/core/policies/core-dependency-policies-and-... therefore I don't think any further action is needed here and consider that this component is OK to add to core in this issue.Comment #74
znerol commentedWe probably should transfer commit credits from #3174760: Mails resembling HTML are corrupted.
Comment #75
adamps commentedI didn't find time for a full review, however from a quick check it looks really good. I like the really solid tests, including for "resembles HTML".
I spotted an outstanding action from #50:
I propose we document mailer_dsn to say that any special characters within passwords and keys must be URL encoded. See #3279696: For DSN transport, document to escape special characters in keys/passwords.
What does anyone think about that?
Comment #76
znerol commentedThanks @AdamPS, rebased and added some docs to the plugin.
Comment #77
catchOne extra point against adding an experimental module here is it would mean exposing it in the module interface as an experimental module, which ironically gives it more exposure than just adding the plugin to core directly.
Comment #78
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".
This does not mean that the patch needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #79
znerol commentedRebased and resolved a conflict in
system.post_update.php.Comment #80
znerol commentedRebased and fixed spelling of Symfony in doc comments.
Comment #81
znerol commentedComment #82
smustgrave commentedMR appears to be unmeragable.
Also is this just waiting on security review? Would be nice to get this into 11.x early for 10.2 testing.
Comment #83
znerol commentedRebased.
Comment #84
smustgrave commentedGoing to mark it and post in #security-discussion if anyone could take a look.
Comment #85
lauriiiTagging with needs framework manager review since the issue is introducing a new API.
Comment #86
znerol commentedRebased and resolved a merge conflict in
system.post_update.php.Comment #87
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".
This does not mean that the patch needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #88
znerol commentedComment #89
smustgrave commentedGoing to restore previous status before the bot.
Comment #90
adamps commentedI raised #3384844: [PP-1] Add security checking for Symfony Mailer transports for the security concerns. I don't think we should even fix that as part of this issue - it should be after #3379794: Add symfony mailer transports to Dependency Injection Container (mail delivery layer) which is postponed on this.
So I suggest we could remove "Needs security review" from this issue, and tackle the security later. Note that core doesn't provide any GUI to change the config setting yet anyway.
Comment #91
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".
This does not mean that the patch needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #92
longwaveComment #93
znerol commentedComment #94
smustgrave commentedGoing to restore status from before. To keep in front of committers
Comment #95
znerol commentedRerolled.
Comment #96
dpiLeft a review. I only touched on the single file.
If this is committed as-is it would make it difficult to override to add compatibility for Symfony Messenger (which we are actively developing in contrib — see MR's).
Also note about event dispatcher.
Comment #97
znerol commentedNo, @dpi. Injecting event dispatcher and the message bus is out of scope in this issue. The goal is to get the composer dependencies in here. And additionally add an experimental mail plugin so people can start to try things out.
Proper dependency injection is worked on in
#1803948: [META] Adopt the symfony mailer component.#3379794: Add symfony mailer transports to Dependency Injection Container (mail delivery layer).Edit: correct issue link.
Comment #98
znerol commentedSee also #30 for the reasoning behind leaving out event dispatcher injection.
Comment #99
znerol commentedRerolled.
Comment #100
dpiThanks @znerol sounds good to me
Comment #101
berdirThis was RTBC before, so lets put it back to that.
For the record, combining adding the dependency and the mail plugin was my idea to have testable usage as well as allowing sites to actually use it for the limited cases that it does support. For example combined with an exposed UI for the setting in the mailsystem module.
But if that actually hinders the main goal (which is developing a new mail API in #1803948: [META] Adopt the symfony mailer component) and delays this from being committed then I'm more than happy to drop that and just get the library in.
Comment #102
adamps commented@Berdir it makes sense to me. It doesn't add a lot of code, and it gives the potential for using any symfony mailer transport (with GUI in contrib). It doesn't appear to hinder the main goal.
Regarding security, I raised #3384844: [PP-1] Add security checking for Symfony Mailer transports which would be fixed after (or part of) #3379794: Add symfony mailer transports to Dependency Injection Container (mail delivery layer) which is postponed on this. On that basis do you think we can remove the "Needs security review" tag??
Comment #103
berdirYes, it makes sense to me as as well, but it's not a deal-breaker so if it helps to get this in, we could remove it. In fact, I recently found https://www.drupal.org/project/symfony_mailer_lite which sites could use in the meantime, and it does much more than just the basic transport and is specifically aimed to allow people to move away from the long deprecated swiftmailer dependency.
Comment #104
adamps commentedThis issue does 3 things:
2) Allows a UI in new contrib module Mailer Transport that can be used with Core, Drupal Symfony Mailer or even Drupal Symfony Mailer Lite. The code already exists in Drupal Symfony Mailer, it just needs to be split out.
@Berdir, this module can potentially be seen as the successor to mailsystem - would you be willing to join me as a maintainer??
3) Allows the HTML mail template to be agreed, and then it can also be used in the new mail system. Also it means we can actually send HTML email from core without any contrib modules at all.
These are all important for the meta goal of #1803948: [META] Adopt the symfony mailer component. Most of what we develop in items 2) and 3) will still be used even after the @Mail plug-in is deprecated and removed. This issue is the starting point of stage 1 of the META, and it puts in place key building blocks to make the following stages easier. Otherwise stage 2 is trying to do too much at once, it becomes even harder.
So I feel that everything in this patch is important. I guess if people feel it's too big we could split it in half. It would definitely be useful to understand what needs to be done to allow this issue to be committed. The overall META issue will likely end up as 20 separate issues, so we might need support from the committers to streamline/prioritise if we want to get it in any time soon.
I removed the "Needs security review" as per #102, and instead added it to #3384844: [PP-1] Add security checking for Symfony Mailer transports - if someone objects then please put it back.
Comment #105
adamps commentedYes I also just discovered symfony_mailer_lite. It's useful to have as a piece of the overall picture. It allows sites using swiftmailer to move to something supported with minimal change.
I would expect that it can gradually be simplified as the code it contains moves elsewhere, then eventually becomes obsolete along with other @Mail plug-ins.
Comment #106
effulgentsia commentedThe MR looks great. Great work!
Comment #111
longwaveCommitted and pushed to 11.x and 10.2.x (after also making a mistake in the 10.2.x cherry-pick).
Excited to see what happens next with the mail system!
Comment #112
adamps commentedAmazing, thanks @longwave. I reckon what happens next is #3379794: Add symfony mailer transports to Dependency Injection Container (mail delivery layer)
Comment #113
berdirAmazing!
> 2) Allows a UI in new contrib module Mailer Transport that can be used with Core, Drupal Symfony Mailer or even Drupal Symfony Mailer Lite. The code already exists in Drupal Symfony Mailer, it just needs to be split out.
> @Berdir, this module can potentially be seen as the successor to mailsystem - would you be willing to join me as a maintainer??
I feel I maintain more than enough modules already that I don't have enough time for so I won't be too sad if mailsystem eventually gets 100% replaced and deprecated, but I'll think about it, can try to do some reviews.
I can see how it could be the base for both drupal symfony mailer and drupal symfony mailer lite, but it would require config/API changes for both of them, assuming it would then manage those transport settings in its own config?
Not sure how that would work for core though in the current form, I think core would need to make selecting/deciding the Transport an official API that can be replaced before that's feasible, so after some of the follow-up issues? Or would you write the configured default transport into the core config setting?
Comment #114
adamps commentedMT (Mailer Transport) module would override one of the services introduced in #3379794: Add symfony mailer transports to Dependency Injection Container (mail delivery layer), perhaps
mailer.transports. I guess it's similar to mailsystem overriding MailManager.Currently the transport code from DSM is copied with minimal change into DSM-L. MT would contain that copied code which would then be removed from the other two.
Correct there would be some minor adjustments to DSM to use the
mailer.transportsservice - which could be the Core version or the MT version (in practice I expect 99% of sites to choose the latter). I plan to do this in a new major version 2.x. Probably it's similar for DSM-L although I didn't look.Comment #115
spokjeThis broke HEAD on 10.2.x with a friendly
Did not had a thorough look at it, but by the looks of the errors, it seems the 2nd attempt on the commit on 10.2.x doesn't contain the changes in composer.json and composer.lock.
Comment #116
znerol commentedComment #119
znerol commentedComment #121
alexpottCommitted 75edd5e and pushed to 10.2.x. Thanks!
Comment #122
longwaveThe dependency was added to the root composer.json instead of core/composer.json.
Comment #124
longwaveComment #125
smustgrave commentedComment #126
spokjeIs that an intentional change in composer.lock?
Comment #127
longwaveI think that is because different core developers are using different Composer versions. Not sure what difference it makes.
This is noted at https://stackoverflow.com/questions/72102111/plugin-api-version-keeps-on... but there is no explanation of what problems it can actually trigger.
Comment #128
spokjeMe neither, just checkin' :)
Comment #129
znerol commentedI'm sorry this is causing so much trouble.
Comment #131
effulgentsia commentedhttps://getcomposer.org/changelog/1.10.0 documents it as just some metadata for 3rd party tools, so I'll proceed for now with the assumption that raising it to reflect the version of Composer used by the person who made the change won't cause any problems.
Therefore, pushed the fix to 11.x and 10.2.x.
Comment #133
effulgentsia commentedI published the CR.
Comment #134
longwaveComment #136
znerol commentedFollow-up on
mailer_dsnconfig: #3399645: Use structured DSN instead of URI in system.mail mailer_dsnComment #137
bkosborneThis seems like a big deal! There's lots of sites relying on the SMTP contrib module that seemingly no longer need to? I created #3424400: Deprecate module in favor of core's built in SMTP mail handling capabilities offered in 10.2.x.