No line endings when using MarkupInterface in legacy mails

Created on 9 July 2025, about 2 months ago

Problem/Motivation

When building an email by adding MarkupInterface instances (most commonly, by calling t()) to the body array, this gives a different result than when using plain strings (and importantly, also a different result as with core Drupal mail or Mail System), in that the text from the body parts is stuck together, without any line ending in between.

Also note that the documentation for hook_mail states "An array of lines containing the message to be sent. Drupal will format the correct line endings for you." (emphasis mine).

Steps to reproduce

  • Build a legacy email by implementing hook_mail.
  • Build the body array by adding at least to MarkupInterface items, e.g.
    $message['body'][] = t('This is the first line.');
    $message['body'][] = t('This is the second line.');
    
  • Trigger the sending of the mail
  • Notice how the two lines are stuck together

Proposed resolution

When building the legacy mail, first render the markup items into a string, and then treat them the same way as a plain string (by putting them in a processed_text render element).

Remaining tasks

  • Create merge request
  • Review
  • Merge

User interface changes

None.

API changes

None.

Data model changes

None.

🐛 Bug report
Status

Active

Version

1.0

Component

Code

Created by

🇳🇱Netherlands eelkeblok Netherlands 🇳🇱

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @eelkeblok
  • @eelkeblok opened merge request.
  • 🇬🇧United Kingdom adamps

    I believe this is "working as designed" and the behaviour is the same in swiftmailer and Drupal Symfony Mailer Lite.

    If you pass in MarkupInterface, then it is treated as HTML. You can control line breaks using HTML tags such as br and p. Sure, Drupal can generate the correct line endings, but they don't have any affect on the layout of HTML.

  • 🇳🇱Netherlands eelkeblok Netherlands 🇳🇱
  • 🇳🇱Netherlands eelkeblok Netherlands 🇳🇱

    Updated the issue summary.

  • 🇬🇧United Kingdom adamps

    My interpretation of this part about the correct line-endings is about ensuring that the email is valid. It is saying that the calling code doesn't have to worry about the details in the RFCs regarding the rules for line-endings. For an HTML email, then the body is MIME-encoded. Still, Drupal (or in fact Symfony Mailer Library) will put line endings according to the rules, but they won't have any effect on the message.

    I agree that this isn't the only way to interpret it. Anyway the comment in hook_mail was likely written before HTML email was even invented. There is no point in having a debate as we can't change it. Any change would alter the emails of all the existing sites in ways that could be undesirable. I feel happy with the current version which matches behaviour elsewhere in Drupal e.g. hook_help().

    The only solution I can see is for you to add in a space or line break in your code.

    PS If you Mail System, then you still need to use something else as a plugin to send the emails. Mail System just allows you to configure which thing to use.

  • 🇬🇧United Kingdom Driskell

    I'm seeing a similar issue but the body is correctly spaced but the issue is there is no

    so the spacing in the email is a bit off.

    Maybe the fix here is to continue to do what it is doing but to apply _filter_autop from Drupal core around the MarkupInterface output. This will add missing paragraphs, whilst leaving alone where there's a block. And should relatively mean any existing HTML emails remain in-tact.

    The processed_text rendering that occurs is already doing _filter_autop but it also strips all HTML and recreates links (it falls back to the fallback format that is usually plain text). So for MarkupInterface would be bad as it will strip HTML (though arguably does any Legacy email support it?).

    Generally it would be just good to have t() strings properly spaced with _filter_autop.

  • 🇬🇧United Kingdom adamps

    Please see #7, especially

    There is no point in having a debate as we can't change it. Any change would alter the emails of all the existing sites in ways that could be undesirable.

    And should relatively mean any existing HTML emails remain in-tact.

    Not true. Your suggestion would add paragraph or break tags wherever this is a line break. Whitespace is not supposed to have meaning in HTML, and this change would break the layout of any email that happens to contain a line break.

    The processed_text rendering that occurs is already doing _filter_autop but it also strips all HTML and recreates links (it falls back to the fallback format that is usually plain text). So for MarkupInterface would be bad as it will strip HTML (though arguably does any Legacy email support it?).

    Yes but the processed text rendering only occurs for plain text emails (not instance of MarkupInterface), which is the correct behaviour.

  • 🇳🇱Netherlands eelkeblok Netherlands 🇳🇱

    Actually, I was completely wrong. This particular project has been using Symfony Mailer since the start, so I am unsure what changed (but something must have changed; our lines didn't used to be stuck together like they are now without the patch I created).

    FWIW, and as I pointed out before, it is not true that whitespace does not have any meaning in HTML. Sur, it has very little meaning, namely that any and all whitespace in between elements will be equivalent to a single space, but that can be an essential difference.
    If we do the very minimal and actually add an actual line break, I don't think HTML mails will suffer any consequences;

    will not have a significant difference with

    \n

    . However, for non-HTML mails there is a great deal of difference between "https://example.comThis is the next line." and "https://example.com\nThis is the next line."

Production build 0.71.5 2024