Problem description
Currently the "alternative plain text" (sent in addition to HTML) is quite different from the ordinary "plain text" (if the message is plain text only).
- This difference is presumably accidental and not what sites want. It's more professional if all the mails are consistent and sites don't want to have to test two different methods.
- The "alternative plain text" includes the template but the "plain text" is missing that important feature.
- The "alternative plain text" is generated with
Html2Textand the "plain text" withMailFormatHelper::htmlToText. We should useHtml2Textin both cases (see reasons in #9). - The footers in the alternative plain text sometimes don't look good, especially if converted from a complex layout such as nested tables.
Proposed resolution
- When generating "plain text", use exactly the same code as for "alternative plain text"
- Add an
is_htmlvariable to the template so that sites can provide different markup for plain text, for example as an alternative to complex HTML footers.
Original report
Currently, html2plain conversion is applied to the entire email, not just the content. Given that especially email footers are quite hard to convert from HTML to plaintext generically, it would be great if this could be set in a separate template file just for the plaintext version.
Required ToDos:
- Create a Twig template for plain text messages, analogously to the one already existing for HTML messages.
- Change the html2plain functionality so that it's only applied to the email content, not the entire template.
Perhaps it might be necessary to have two layers of templates: one that defines the headers, footers, etc (for the two formats separately), and one that deals with the actual message display (involving various mail parameters, additional Twig styling).
Hope this makes sense!
| Comment | File | Size | Author |
|---|---|---|---|
| #35 | swiftmailer.plaintext-conversion.3126935-interdiff-28-35.txt | 1.7 KB | adamps |
| #35 | swiftmailer.plaintext-conversion.3126935-35.patch | 14.09 KB | adamps |
| #28 | swiftmailer.plaintext-conversion.3126935-28.patch | 14.09 KB | adamps |
Comments
Comment #2
adamps commentedThanks for the idea.
Unfortunately I feel this is much too specialist to your specific situation for Swift Mailer core module. It adds a lot of complexity. It would be disruptive to existing templates and non-back-compatible. The fact that you are unsure and put 'perhaps' in your description indicates to me exactly the problem which is that one could continue to invent more and more complexity in this direction but it's not really clear that any of the other 35000 users of the module would find it especially useful.
The automatic plain text is an optional feature. If you want to generate your own then the Swift Mailer module will respect it.
Comment #3
adamps commentedOK, so I agree with the initial problem you are seeing. I propose a different and much simpler way to resolve it - see issue summary.
What do you think?
Comment #4
geek-merlinThanks both! This is a really interesting problem. And i think i remember that quite some people had pain points with this.
I'm not so decided what's the best solution wrt cost/benefit ratio. Template suggestiona offer big fix-my-custom-needs power, while being quite cheap in the end.
Let's get some feedback on this.
Comment #5
geek-merlin> We should decide which one [MailFormatHelper::htmlToText vs Html2Text] is better and use is in both cases.
My gut feeling is the answer will be "YMMV"... So i'm not opposed to make this configurable (maybe in the theme layer?).
Comment #6
adamps commentedYes you are right - good to get some feedback. Looking again I think that this issue has touched upon 3 separate topics.
1. When generating the plain text alternative, the current code will use the HTML template then convert to plain. That seems wrong and instead we should do the same as when generating a plain text mail - whatever we decide that should be. This change is non-BC and we should do it before beta.
2. When generating plain text (either alternative or body) it could be useful to have a template something like swiftmailer-plain.html.twig. You are right this is a good idea. However we can add this later in a fully BC way (the default template would be empty) so there is no rush. I feel it would be clearer to create a separate issue for this.
3. Some sites might like to have a complex system of templates with multiple layers and so on. Well Twig allows that with the include mechanism. This seems like it is a site specific choice and not something to include in the core module.
Comment #7
geek-merlinThanks for elaborating. I fully agree on all points.
Comment #8
geek-merlin> MailFormatHelper::htmlToText vs Html2Text
Some research indicates that we want to stick with Html2Text until reasons.
So let's focus on the other questions like themability.
Comment #9
adamps commentedI have raised #3130818: Add a template for plain text mails which would be the ideal place to focus on themability.
In the meantime the points in the IS seem entirely valid so let's use this issue to solve them. Thanks for adding related issues which are useful.
In #2830384: Deprecate MailFormatHelper in favor of html2text/html2text library @Berdir suggests to deprecate MailFormatHelper in core. It has barely been maintained and html2text has 450k installs on packagist.
#2940969: Add setting to choose between Html2Text and MailFormatHelper::htmlToText points out that any change without adding an option would be a BC break. However we are just starting a new branch so it is the ideal time to break BC to clear out some deprecated code.
We already use html2text for the plain text alternative and this is documented in the swiftmailer README.
We only use MailFormatHelper when sending plain-text mails for content that was HTML. That's not a main use case of this module - core can already format plain-text mails. Presumably most sites using this module want to send HTML mails. So perhaps most people won't even notice??
To my mind this all strongly suggests that we should stop using MailFormatHelper and use html2text consistently. html2text has lots of config options so we could add a hook to allow customisation of those.
Before we add that complexity I would like so see some clear scenarios where this would be required.
Comment #10
adamps commentedComment #12
adamps commentedComment #13
adamps commentedThis patch solves problems 1. and 2. in the IS. It doesn't provide any configuration to choose MailFormatHelper but we could add that later in a BC way.
Comment #14
PhilippVerpoortDear both,
apologies that it took me a while to get back to you. Thanks so much to both of you for your time and effort.
My main points:
Regarding point 2: I agree that being consistent with the function used for HTML to plaintext conversion is a good thing. Perhaps it might be okay to break BC regarding the plain-text conversion instead of creating a lot of work and complexity that probably nobody is ever going to care about. As you said, I doubt that many people would use Swiftmailer to create plain-text messages anyway, and for those people who do the difference in output between the two functions probably doesn't matter that much. And if you're planning to start a new branch, then I agree it's the perfect timing to clear out deprecated code. If somebody objects, they can always write their own little patch to replace the Html2Text function with another function of their choosing.
Regarding your resolution of point 1: I'm not sure I agree. You're making the assumption that the
swiftmailer.html.twigtemplate file contains nothing that would be worth including when converting to plaintext. However, I think it's rather common to have something in there that would be worth keeping. Specifically, it would be great to be able to display any manually populated message parameters in this TWIG template, and ideally this should carry over to the auto-generated "alternative plain text". E.g. I have something like this in that file:So this bit you want to keep in the html2text conversion, whereas you don't want to include things like logos, divs, boxes/frames around the text, preheaders (the message summary bit displayed in the inbox by some modern email apps), etc.
Having given it another thought (and I feel more confident about it now!), I believe the only clean way of handling this is to have two sets (or layers) of templates. One for the inner mail content (that processes the
{{ body }}as well as other message params) plus an outer mail styling (that includes the<html> ... </html>tags and would add preheaders, frames, logos, etc.I know you mentioned that this added layer of complexity is unnecessary because it can already be accomplished by site builders through the TWIG sub-template functionality (e.g. through the
{% include ... %}statement). I would normally completely agree with you, but the only reason why this goes wrong has to do with the HTML2Plain conversion. If it weren't for that, I'd agree, but if you want to resolve this in a clean manner, you need another layer of templates.I don't think adding these templates would necessarily have to break BC. You can just set the new templates to print back the output of the sub-template.
Let me give an example.
Say a module creates this content:
Then a sensible TWIG theming would look like this:
Example
swiftmailer.twig.htmlcontains:Example
swiftmailer-plain.twig.htmlcontains:The
{{ plain }}variable is either the plain-text output of the respective module that created that email, or it's a HTML2Text version of{{ body }}. Now because most site builders are not going to care about writing their ownswiftmailer-plaintemplate file for this, they'll probably just want to use a default template like this:Default
swiftmailer-plain.twig.htmlcontains:Where
{{ plaintext_from_template }}is now the plaintext conversion of the entireswiftmailer.twig.htmltemplate output, not just{{ body }}.On top of that, you allow all the email styling stuff to go into two separate templates:
Example
swiftmailer-footer.twig.htmlcontains:Example
swiftmailer-plain-footer.twig.htmlcontains:And of course these last two new templates should default to the bare minimum in order to ensure full BC.
I know this looks like an awful lot of changes and new templates, but IMHO this is the only way of dealing with this properly. It gives a lot of flexibility to people who want to do email styling correctly, yet those who just want to keep it simple will be able to stick with just using one template.
I know you could probably argue that all of this stuff is irrelevant and that all of the content creation should happen inside the module (perhaps through a separate template in there), and that all that the Swiftmailer module should ever care about is how to turn the body and plaintext of the message into an HTML or plaintext email, yet my personal experience is that it's a hell of a lot easier to add a few message params through a hook and then do all that in the
swiftmailer.twig.htmltemplate than add another template myself and completely rewrite the content of an email produced by a module inside a hook.I think email styling really matters to make D8 more competitive, and so I think finding ways to make the styling both flexible but also work out-of-the-box is important.
Let me know what you think! Also I fully understand if you prefer to move this discussion to another issue.
Comment #15
adamps commented@PhilippVerpoort
Thanks for a detailed explanation.
I do prefer to split into separate issues please. I think it will work much better if we check this issue in first, then that leaves a better structure for considering templates. Please can we continue the discussion about templates in #3130818: Add a template for plain text mails?
From reading the first part of your comment I deduce that you are in support of the patch on this issue - great. If you are willing to do a review or test it then that would be even better.
Comment #16
adamps commented@PhilippVerpoort Apologies I now realise I was too hasty to reply without properly reading your comment. You have carefully thought things through and explained it very well which is a big help. I admit that when I saw about adding layers of templates I had a strong negative reaction without properly analysing what you said. I am also now coming to believe that my idea to split the templates into a separate issue is wrong because the two matters are closely linked.
So let me try to recap what you are saying and put forward some ideas:
Currently the plain text alternative is generated like this:
Whereas a plain text mail is generated like this
This issue aims to use the same code for both cases.
Option 1 I had imagined the we would combine the two with code like this
However you have pointed out that there might be significant overlap between the two templates. One contains HTML and the other contains plain text so it's difficult or impossible to share content.
Option 2 We can instead use code like this:
This is what you are proposing except that I have left things very open as to how the template would be different in the plain text case. I am still very reluctant to try to impose a specific hierarchy of template layers because it seems over-complex and risks being specific to a particular use case.
Here is my alternative idea. We can add a template variable is_plain which is a boolean. If the site wants to have parts of the template that are different between HTML and plain then they can simply use
What do you think?
Comment #17
adamps commentedComment #19
adamps commentedComment #20
adamps commentedComment #21
adamps commentedI tested a bit more and it's still not quite right. In the plain text alternative URLs are converted to links then remain in the output twice, something like this
Also the line breaks are quite muddled.
Here is a new patch that fixes these. It has a call to an internal function
_filter_autopwhich I can fix but lets just check if it passes tests and people like it.Comment #23
PhilippVerpoortWow, I'm impressed! Thanks for putting all your hard work into this. And thanks for reading and re-considering my answer so carefully. I also agree it's better to resolve all these things at once because they're intrinsically linked.
I actually think this is a good idea! I was wondering, if it were possible to combine this with another approach:
Could we perhaps wrap everything that is supposed to be converted from HTML to plain in a
<div> ... </div>? And then only feed the content of that div to the html2text function?An example for a
swiftmailer.html.twigfile:So then you've got to make sure you pull out all content inside any
<div class="to-be-converted-to-plain"> ... </div>environments. I suppose you could use the DOM extension? (Which I believe is a requirement of Drupal 8?). An example:Completely untested but just an idea.
What do you think about this?
Sorry, I haven't had a chance to look at your patches. Perhaps you want to have a think about my proposed change and perhaps try to fix that one fail that your last patch produced? I'll see if I can take a look at your patch and perhaps even get it tested in the meantime.
Concerning this:
To be very honest, I wouldn't worry about that too much. I think that's just something somebody would have to live with if they're relying on automated html to plaintext conversion of an email. The only way to stop this from happening is to stop Drupal from converting links of that type to ones enclosed by
<a href="...">...</a>tags (which I'd definitely not recommend for the sake of usability for anyone writing HTML emails). An alternative way would be to check if the href bit inside the<a>tag matches the bit enclosed by that tag, and then remove those<a>...</a>tags. You could do that without too much trouble I presume...Comment #24
PhilippVerpoortOops, that was an unintended change of the issue status.
Comment #25
adamps commentedThanks @PhilippVerpoort
I think you can get what you want without the special divs processing. Could you do it like this? The links will be converted to a suitable plain text equivalent automatically so you don't need to use an if test there.
Actually I think we can have the best of both worlds - try the current patch and you should see that the HTML version has a clickable link but the plain text version doesn't have the link twice.
Comment #26
adamps commentedComment #28
adamps commentedComment #29
PhilippVerpoortYour solution makes complete sense, and will work much better than anything I had suggested!
I installed the patch, and it works like a charm! Amazing, thanks!!!
I'll set it to "Needs review", and if one more person could find the time to confirm this is working, then I guess we can consider this reviewed.
Comment #30
geek-merlinI did not completely dig everything but this looks amazing!
Comment #31
PhilippVerpoort@geek-merlin: Would you mind giving it a quick test so we know it's working and we can get this committed?
Just install the patch and add some
{% if is_html %}statements to your swiftmailer TWIG template. If it works for you as well, I think we can consider this done!The template I'm using looks like this. Perhaps this is a good starting point?
Comment #32
adamps commented@PhilippVerpoort Thanks for testing. I think for me if one person has tested, plus me that's enough. We are going to make a Beta and if people find bugs then we can fix them.
I feel that the main priority is to check that the concepts are right. We'd prefer not to make any more non-back-compatible changes after releasing a Beta. If anyone has comments on that then I'd like to hear them. However D9 has been released so we shouldn't wait too long before making a compatible release here. I propose to check in at the end of this week if there is no more feedback.
Comment #33
PhilippVerpoortSure, sounds great! Amazing!
Comment #34
geek-merlin> Thanks for testing. I think for me if one person has tested, plus me that's enough.
+1 from me on everything, unfortunately i'm super low on bandwidth these days.
Comment #35
adamps commentedGreat. One last tweak to remove the call to the internal function _filter_autop().
Comment #37
adamps commented