zbateson / mail-mime-parser

An email parser written in PHP
https://mail-mime-parser.org/
BSD 2-Clause "Simplified" License
442 stars 56 forks source link

Set order of text and html part #170

Closed postme closed 1 year ago

postme commented 3 years ago

Hi Zaahid, thank you for the nice shoutout on the frontpage :-)

I'm running into a small issue with regards to order of setTxtPart and setHtmlPart. I'm using both functions to set a text part and a html part. The resulting document has the html part first and the text part as the last part. Is there a way to influence the order of text part and html part? I'm asking because RFC 1341 section 7.2.3 states that mime parts should be added in order of preference. With the current ordering the email message shows the text part as the most preferred part as it is added as the last part. In GMail this leads to behaviour that it shows only the text part and not the html part.

Kind regards Meint

p.s. I switched around the order of operation but that didn't make a difference in the the sequence of html part -> text part

zbateson commented 3 years ago

Hi Meint, you're most welcome, and also thank you for the sponsorship :)

Actually that was part of the original development... this might've been long enough ago for it to not matter, and mail clients now might be better behaved. This was when we were working on the 'write' functionality back in 2016:

Email clients get a bit upset when presented with a signed message and sometimes don’t know which mime part to show, if they’re unsure they’ll take the first mime part which tends to be text/plain rather than text/html. Would you see a way to put in the text/html mime part as the first part of the signed smime structure?

Based on RFC 1341 though, you're absolutely right. The preferred part is the last part and HTML should default to the second part. Also it might make sense to not force that somehow, so a user can change that if they want.

I'm not sure which clients you were testing with back in the day that were showing the first alternative part though. Any ideas, or we shouldn't worry about them since it was almost 5 years ago?

postme commented 3 years ago

Hi Zaahid, wow you have a great memory, I completely forgot about that discussion. I can't recall anymore which mail client misbehaved at the time but if the ordering is configurable it should not be an issue per se I think?

zbateson commented 3 years ago

Yeah, I think that's the only way to go really -- change the default and make it configurable :+1:

zbateson commented 3 years ago

Actually it looks like my memory's not that great after all, because I didn't remember that this is only done for a signed message :).

When you call $message->setAsMultipartSigned() is when the switch happens, it 'ensures' the html part is first.

If I remove the code that does that, and keep the default, you could then do this (you might need some null checks added though, and maybe a check on the parent's content type to ensure it's multipart/alternative if it might not always be -- I think in your case it is):

$htmlPart = $message->getHtmlPart();
$parent = $htmlPart->getParent();
if ($parent->getChild(0) === $htmlPart) {
    $parent->removePart($htmlPart);
    $parent->addChild($htmlPart);
}

Would that work for you for now? The reason I'm doing it this way (getting html part first instead of finding the alternative part) is because the new version I'm working on doesn't use PartFilter anymore, it replaces it with a much simpler callback method that can be used to filter/find parts, so this way is forward-compatible at this point.

Let me know if that works for you and I'll remove the code that needs to be removed.

zbateson commented 3 years ago

Hi @postme --

I've put up a branch 'fix-170' that doesn't reorganize parts of a multipart/alternative when calling setAsMultipartSigned() if you want to give it a go.

Thanks, Zaahid