Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mobile GMail clients do not display images #327

Closed
Myp3a opened this issue Apr 4, 2025 · 8 comments
Closed

Mobile GMail clients do not display images #327

Myp3a opened this issue Apr 4, 2025 · 8 comments

Comments

@Myp3a
Copy link

Myp3a commented Apr 4, 2025

Hello! I'm testing my fresh Mox setup to check that all features work as expected :)

Got an issue with images, they aren't displayed properly in mobile GMail clients (both iOS and Android). Android client shows a broken image, iOS client also spews image content as text.

iOS GMail screenshot

Image

Other clients works fine, including: GMail Web, Mox Webmail, macOS Mail, Outlook (macOS).

Judging from raw messages, could this be an encoding issue? Mox one shows koi8-r, while GMail uses UTF-8. Attaching these messages below.

gmail.txt
mox.txt

Running Mox v0.0.14, domain pcho.la, configured properly (except for DNSSEC).

@mjl-
Copy link
Owner

mjl- commented Apr 4, 2025

Thanks for reporting, and the examples, I can reproduce the issue with the gmail apps on iOS and Android. I sent myself another message, with an ascii plain text part and an image, and it shows the same behaviour, so it isn't a utf-8 vs koi8-r encoding issue. I suspect the mox imap server is sending data in a form the gmail app doesn't expect. It is asking for 123 UID FETCH 123 (BODY.PEEK[1] BODY.PEEK[2]), and it's getting data back that looks correct. On iOS, the gibberish for my PNG image includes the PNG header, so it's getting the right bytes, just not showing it as an image.

Will investigate more.

@mjl-
Copy link
Owner

mjl- commented Apr 5, 2025

After quite some testing I found a way to get the gmail app to display images when connected to the mox imapserver. It looks like a bug in the gmail app to me, but we can work around it. However, the proper fix is a little bit more involved than the quick fix I made. Some details:

The gmail app does a "UID FETCH" to get attributes about messages without downloading them in full. Among others, it asks for BODYSTRUCTURE, which returns the MIME structure of the message file. For my simple test message, with a multipart/mixed, and a text/plain and an image, this is what dovecot returns:

BODYSTRUCTURE (("text" "plain" ("charset" "us-ascii") NIL NIL "7bit" 6 1 NIL NIL NIL NIL)("image" "png" ("name" "testbeeld.png") NIL NIL "base64" 26516 NIL ("attachment" ("filename" "testbeeld.png")) NIL NIL) "mixed" ("boundary" "33bcd09587eff74d12124fa7409e96eb04833266c103edab6fc858f437a7") NIL NIL NIL)

And this is what mox returns:

BODYSTRUCTURE (("TEXT" "PLAIN" ("CHARSET" "us-ascii") NIL NIL "7BIT" 6 1)("IMAGE" "PNG" ("NAME" "testbeeld.png") NIL NIL "BASE64" 26516) "MIXED" ("boundary" "33bcd09587eff74d12124fa7409e96eb04833266c103edab6fc858f437a7"))

For the text/plain part, mox doesn't have the last 4 NILs. For the image/png part, mox doesn't have the nil [attachment] nil nil, and for the outer mixed part (at the end) mox doesn't have the 3 NILs.

Adding these fields to the mox output makes the gmail app interpret the attached image as image instead of binary text.

Those missing/additional fields are optional according to the RFCs (https://www.xmox.nl/xr/dev/rfc/9051.html#L6023, https://www.xmox.nl/xr/dev/rfc/9051.html#L6366), and mox doesn't add them because the data required to send them isn't currently in the message index database, and calculating them for each "fetch" command is relatively expensive, requiring parsing the message file from disk. Also see #217 for an earlier report about the extra fields in the BODYSTRUCTURE response. Other than the content-disposition (which is useful), the fields represent the parsed content-md5, content-language and content-location headers (which I suspect aren't used much or at all in practice).

I think the gmail app should recognize that the imapserver isn't sending those fields (content-disposition in particular), so it should request the part headers to parse those fields itself. But it doesn't do that, and somehow decides the part should be displayed as text, which looks like a bug to me.

I think mox should be changed to always send all the optional fields in the BODYSTRUCTURE responses, and start parsing those content-* headers and keeping track of them in the message index database too so mox can make the fetch responses efficiently. Messages currently in the index database would need to be reparsed. We don't have a mechanism yet to do that automatically, but there is a command for admins to do it manually. Will try to implement this in the coming days.

mjl- added a commit that referenced this issue Apr 5, 2025
…ly for content-disposition

The gmail iOS/Android app were showing mime image parts as (garbled) text
instead of rendering them as image. By returning all the optional fields in the
bodystructure fetch attribute, the gmail app renders the image as expected by
the user. So we now add all fields. We didn't before, because we weren't
keeping track of Content-MD5, Content-Language and Content-Location header
fields, since they aren't that useful.

Messages in mailboxes have to be reparsed:
	./mox reparse

Without reparsing, imap responses will claim the extra fields
(content-disposition) are absent for existing messages, instead of not claiming
anything at all, which is what we did before.

Accounts and all/some mailboxes can get their "uid validity" bumped ("./mox
bumpuidvalidity $account [$mailbox]"), which should trigger clients to load all
messages from scratch, but gmail doesn't appear to notice, so it would be
better to remove & add the account in gmail.

For issue #327, also relevant to issue #217.
@mjl-
Copy link
Owner

mjl- commented Apr 5, 2025

The commit just now ensures the other bodystructure fields are returned in the IMAP fetch responses too. Existing messages should be reparsed to update the parsed form in the message index database: ./mox reparse (after updating). For the gmail app, it looks like it is necessary to remove and readd the account to force it to fetch messages again (also see commit message).

For a binary with this commit, see https://www.xmox.nl/b/#2defbce0bc05d93c6c4c63f1d2f8d545879d311b.

@Myp3a
Copy link
Author

Myp3a commented Apr 5, 2025

Wow, even a prebuilt binary! Thanks, this one works, after reparsing and relogging pictures are displayed on both devices.

However, there are a few differences between mail clients about image displaying.

Message sent with Outlook: properly displayed everywhere.

Message sent with Android GMail (image attached only as attachment, not as inline image):

  • Outlook: everything is fine;
  • Apple Mail: text is fine, image inlined after text;
  • iOS Mail: text is duplicated, image inlined after text;
  • iOS GMail: text is duplicated, image is fine;
  • Android GMail: everything is fine;
  • Mox webmail: everything is fine.

Message sent with iOS GMail (image attached as attachment and inlined into text):

  • Outlook: everything is fine;
  • Apple Mail: text is fine, image inlined and duplicated;
  • iOS Mail: text is fine, image inlined and duplicated;
  • iOS GMail: everything is fine (image displayed both inline and as attachment);
  • Android GMail: everything is fine (image displayed both inline and as attachment);
  • Mox webmail: text is fine, image shown as broken (attachment is fine).

Attaching examples below.

from_outlook.txt (received)

from_android.txt (received)

from_android_sent.txt (sent)

from_ios.txt (received)

from_ios_sent.txt (sent)

@mjl-
Copy link
Owner

mjl- commented Apr 7, 2025

Interesting messages, thanks for providing them, very helpful.

Summary: I think how the various email clients display these messages, with duplicate text and/or attachments is somewhat understandable. I'm going to modify the mox webmail to show the broken image sent with the gmail app on iOS.

More detail:

The outlook message has this MIME structure:

multipart/related
	multipart/alternative
		text/plain
		text/html
	image/jpeg

The nested multipart/alternative tells the client to show either the plain or html version of the message. The HTML part refers to the image with a <img src="cid:..."> element, with the cid value the same as the Content-ID header in the image/jpeg part. Mail clients will typically assume the HTML part refers to the "related" files (i.e. showing them in the message), but will show the "related" files inline (for images) or as attachments when the plain text part is displayed, because there is no way for the plain text to refer the the related files. This sometimes causes useless logo images from logo files to be displayed when viewing a text version, but at least doesn't hide images that are only referred to from the html part.

There's something funny with the gmail android messages. The "sent" message has this form:

multipart/mixed
	text/html
	text/plain
	image/jpeg

While the received version has this form:

multipart/mixed
	text/html
	image/jpeg

I don't know if the message was rewritten the received message, or whether the stored "sent" version was actually different than what the gmail android app submitted over smtp. The "sent" messages are both (ios and android) regenerated, with different multipart boundaries, but the same message-id.

Anyway, displaying the text twice is expected with mime structure of the "sent" version. More clients I tested do that (with the android "sent" version). All parts of a multipart/mixed message should be considered part of the message content. So ideally, all parts should be shown, including both the text and html version, which have the same textual contents. This seems like a bug in the gmail app to me, it should be wrapping the text/plain and text/html parts in a multipart/alternative.

For the message sent with ios gmail, I don't know why ios mail shows a download button. I suspect it's just trying to be helpful, and that you would see the same behaviour when fetching the message over other mail servers. I tried getting ios mail to connect to a dovecot test server I have on a non-standard port, but I couldn't get it to set up the account...

Then for the broken image in the webmail with the gmail ios message: The <img src="cid:..."> isn't replaced properly by the image content. This is because mox only replaces cid's/Content-IDs found in multipart/related types, not in any other types (multipart/mixed). Using Content-Id's from all parts causes the image to show, so I'm going to make that change. Outlook on iOS also shows a broken image.

mjl- added a commit that referenced this issue Apr 7, 2025
…her parts, not just when there is a multipart/related in the message

The gmail apps generate messages consisting of multipart/mixed, with text/html
referring to a sibling image/jpeg. We weren't resolving that cid before.

Related to issue #327.
@mjl-
Copy link
Owner

mjl- commented Apr 7, 2025

Commit above should show the inline image from the gmail ios version in the mox webmail.

Btw, the mox webmail isn't showing duplicate text because we either show plain text parts, or an html part, but when we show an html part, we never show anything else at the moment. This is related to needing to know the inner size of html parts while isolating html parts in an iframe with CSP headers. I plan to look into that at some point, and change the webmail to start showing all the parts in a multipart/mixed, which will cause us to show duplicate content as well...

Due to the various multipart forms composed by email clients, other email clients have various heuristics about which parts to show. It's understandable not all email clients have the same heuristics...

mjl- added a commit that referenced this issue Apr 7, 2025
…1 is a message

MIME returns the part headers. If 1 is a message, i.e. a message/rfc822 or
message/global, for example when top-level is a multipart/mixed, we were
returning the MIME headers from the message, not from the part.

We also shouldn't be returning a MIME-Version header or the separating newline
for MIME. Those are for MIME headers of a message, but the "MIME" fetch body
part is always about the part.

Found after looking into FETCH BODY handling for issue #327.
@mjl-
Copy link
Owner

mjl- commented Apr 7, 2025

The commit just now shouldn't affect any these messages. It's mostly for messages that contain other messages in full.

Btw, after adding more test messages to my mailbox, I noticed some got grouped (as threads due to same subject), and some mail clients then show the multiple attachments (from all messages in a thread) combined in the list view. The individual message views then show either just the inline image, or also a download button (which is probably what you've been seeing), but at least not another duplication (what I hope you haven't been seeing).

@Myp3a
Copy link
Author

Myp3a commented Apr 8, 2025

Thank you, webmail is fine now.

Also thanks for the explanation about text and image duplication. I probably should report this to GMail team and find another email client that sends correct messages.

@Myp3a Myp3a closed this as completed Apr 8, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants