Message body completely hidden when text/plain is followed by an unrelated text/html part (e.g., mailing list footers)
@ChristophWurst is already working on this.
Since Mar 31, 2026.
- Dominant language
- JavaScript
- Stars
- 1k
- Forks
- 348
- Avg merge
- 12h 28m
- Merged PRs (30d)
- 91
Description
Steps to reproduce
- Send a plain text email to a mailing list or through a gateway that appends an HTML footer/signature.
- The resulting email will have a multipart/mixed structure containing a text/plain part (the actual message) and a text/html part (the appended footer).
- Open the email in Nextcloud Mail.
- Observe that only the HTML footer is rendered. The main message is gone.
Expected behavior
Nextcloud Mail should display both parts, or at least be smart enough to detect if the HTML part is just an unrelated addition (like a footer) rather than an alternative version of the plain text body.
Actual behavior
Nextcloud Mail only renders the text/html part. The main message content is completely lost/hidden from the UI.
Mail app version
5.6.14
Nextcloud version
31.0.14
Mailserver or service
Dovecot imap own server
Operating system
Ubuntu 24.04
PHP engine version
PHP 8.3
Nextcloud memory caching
'memcache.local' => '\OC\Memcache\APCu', 'memcache.distributed' => '\OC\Memcache\Redis',
Web server
Nginx
Database
MariaDB
Additional info
DESCRIPTION
When Nextcloud Mail receives a multipart/mixed email containing a text/plain body and a text/html attachment/footer, it only renders the HTML part and completely discards the plain text message.
This happens very often with mailing list software (like Sympa or Mailman) or corporate antivirus gateways. The original sender sends a pure text/plain email, and the server appends an unsubscribe link or signature in text/html. Because an HTML part exists, the Nextcloud Mail parser prioritizes it and the user only sees the footer, making the actual email completely invisible unless they check the raw source.
Proposed Solution
A robust fix is to check if the text/plain content actually exists within the text/html content. If it doesn't (meaning the HTML is just a discrete footer/banner), both should be concatenated.
I successfully patched my local instance by modifying the getHtmlBody() method in IMAPMessage.php with this logic:
public function getHtmlBody(int $id): string {
$html = $this->htmlMessage;
$plainTextTrimmed = trim($this->plainMessage);
if ($plainTextTrimmed !== '') {
$htmlTextStripped = strip_tags($html);
// Normalize whitespace to prevent false negatives
$plainNormalized = preg_replace('/\s+/', ' ', $plainTextTrimmed);
$htmlNormalized = preg_replace('/\s+/', ' ', $htmlTextStripped);
// Take a snippet of the plain text to look for it inside the HTML
$snippet = mb_substr($plainNormalized, 0, 60);
// If the plain text snippet is NOT in the HTML, the HTML is just an unrelated footer
if (mb_strpos($htmlNormalized, $snippet) === false) {
$plainHtml = '<div style="white-space: pre-wrap; font-family: inherit; margin-bottom: 20px;">' . htmlspecialchars($plainTextTrimmed) . '</div>';
$html = $plainHtml . '<hr style="border: 0; border-bottom: 1px solid #ccc; margin: 20px 0;">' . $html;
}
}
return $this->htmlService->sanitizeHtmlMailBody($html, [
'id' => $id,
], function ($cid) {
$match = array_filter($this->inlineAttachments,
static fn ($a) => $a['cid'] === $cid);
$match = array_shift($match);
if ($match === null) {
return null;
}
return $match['id'];
});
}
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.