Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
Date: Wed, 26 Jan 2022 12:21:37 +0100
From: Bob <bob@domain.tld>
To: Alice <alice@domain.tld>
MIME-Version: 1.0
Subject: inlined attachment
Message-ID: <Mime4j.16b.d30609c122843f4e.196a380f8b9@domain.tld>
Content-Type: multipart/related;
boundary="-=Part.16d.b16547c587c987fd.196a380f8d4.b92d6af2f0294389=-"

---=Part.16d.b16547c587c987fd.196a380f8d4.b92d6af2f0294389=-
Content-Type: multipart/alternative;
boundary="-=Part.16c.d54cec4b999aebb5.196a380f8d2.7189347f48aceda7=-"

---=Part.16c.d54cec4b999aebb5.196a380f8d2.7189347f48aceda7=-
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Accept-Language: fr-FR, en-US, vi-VN, ru-RU, ar-TN, it-IT, de-DE
Content-Language: vi-VN


start[Screenshot 2025-05-06 at 09]end


---=Part.16c.d54cec4b999aebb5.196a380f8d2.7189347f48aceda7=-
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Accept-Language: fr-FR, en-US, vi-VN, ru-RU, ar-TN, it-IT, de-DE
Content-Language: vi-VN

<div><br></div><div>start</div><div><img src=3D"cid:e612b3e0-2a24-11f0-aacf=
-77a69744ec20" alt=3D"Screenshot 2025-05-06 at 09" style=3D"max-width:770px=
;" data-mimetype=3D"image/png"></div><div>end</div><div><br></div><div><br>=
</div>
---=Part.16c.d54cec4b999aebb5.196a380f8d2.7189347f48aceda7=---

---=Part.16d.b16547c587c987fd.196a380f8d4.b92d6af2f0294389=-
Content-Type: image/png;
name="=?US-ASCII?Q?Screenshot_2025-05-06_at_09.50.27.png?="; charset=base64
Content-Disposition: inline
Content-Transfer-Encoding: base64
Content-ID: e612b3e0-2a24-11f0-aacf-77a69744ec20

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
wsRirMVMixqL3ywplmzLTMu1lucs31tZWyVaLbSqt3purWfNsy6wrrG+Z0Oz8bWZYlNpc92WaMu2
zbbdYHvFDrVztcu0q7C7bI/au9mL7TfYt40gjPAYIRlROeKWg7oDxyHfocbhoSPTMdyx0LHe8eVI
i5HJI1eMPDfym5OrU47TNqe7o7RHhY4qHNU46rWznbPAucL5+mja6KDRc0Y3jH7lYu8ictnoctuV
4TrWdaFrs+tXN3c3mVutW6e7hXuq+3r3W2wddhR7Cfu8B8HD32OOR5PHR083zzzP/Z5/eTl4ZXvt
9Ho+xnqMaMy2MY+9zbz53lu8231YPqk+m33afU19+b6Vvo/8zP2Eftv9nnFsOVmcXZyX/k7+Mv9D
/u+5ntxZ3BMBWEBwQHFAa6B2YHxgeeCDILOgjKCaoO5g1+AZwSdCCCFhIStCbvGMeAJeNa871D10
VujpMPWw2LDysEfhduGy8Max6NjQsavG3ouwjJBE1EeCSF7kqsj7UdZRU6KORBOjo6Irop/GjIqZ
GXMulhE7KXZn7Ls4/7hlcXfjbeIV8c0J9ISUhOqE94kBiSsT28eNHDdr3KUkgyRxUkMyKTkheXty
z/jA8WvGd6S4phSl3JxgPWHahAsTDSbmTDw6iT6JP+lAKiE1MXVn6hd+JL+S35PGS1uf1i3gCtYK
Xgj9hKuFnSJv0UrRs3Tv9JXpzzO8M1ZldGb6ZpZmdom54nLxq6yQrE1Z77Mjs3dk9+Yk5uzJJeem
5h6WaEuyJacnG0+eNrlNai8tkrZP8ZyyZkq3LEy2XY7IJ8gb8nTgh36Lwkbxk+Jhvk9+Rf6HqQlT
D0zTmiaZ1jLdbvri6c8Kggp+mYHPEMxonmk6c97Mh7M4s7bMRmanzW6eYz5nwZyOucFzq+ZR52XP
+7XQqXBl4dv5ifMbFxgtmLvg8U/BP9UUaRTJim4t9Fq4aRG+SLyodfHoxesWfysWFl8scSopLfmy
RLDk4s+jfi77uXdp+tLWZW7LNi4nLpcsv7nCd0XVSq2VBSsfrxq7qm41a3Xx6rdrJq25UOpSumkt
da1ibXtZeFnDOot1y9d9Kc8sv1HhX7FnveH6xevfbxBuuLrRb2PtJqNNJZs+bRZvvr0leEtdpVVl
6Vbi1vytT7clbDv3C/uX6u0G20u2f90h2dFeFVN1utq9unqn4c5lNWiNoqZzV8quK7sDdjfUOtRu
2cPcU7IX7FXs/WNf6r6b+8P2Nx9gH6g9aHlw/SHGoeI6pG56XXd9Zn17Q1JD2+HQw82NXo2Hjjge
2dFk2lRxVPfosmPUYwuO9R4vON5zQnqi62TGycfNk5rvnhp36vrp6NOtZ8LOnD8bdPbUOc654+e9
zzdd8Lxw+CL7Yv0lt0t1La4th351/fVQq1tr3WX3yw1XPK40to1pO3bV9+rJawHXzl7nXb90I+JG
2834m7dvpdxqvy28/fxOzp1Xv+X/9vnu3HuEe8X3Ne+XPjB8UPm77e972t3ajz4MeNjyKPbR3ceC
xy+eyJ986VjwlPa09JnJs+rnzs+bOoM6r/wx/o+OF9IXn7uK/tT6c/1Lm5cH//L7q6V7XHfHK9mr
3tdL3ui/2fHW5W1zT1TPg3e57z6/L/6g/6HqI/vjuU+Jn559nvqF9KXsq+3Xxm9h3+715vb2Svky
ft+nAAaUR5t0AF7vAICWBAADnhup41Xnw76CqM60fQj8J6w6Q/YVNwBq4Td9dBf8urkFwN5tAFhB
fXoKAFE0AOI8ADp69GAdOMv1nTuVhQjPBpt5X9Ny08C/Kaoz6Q9+D22BUtUFDG3/BXkhgywpQj4b
AAAAimVYSWZNTQAqAAAACAAEARoABQAAAAEAAAA+ARsABQAAAAEAAABGASgAAwAAAAEAAgAAh2kA
BAAAAAEAAABOAAAAAAAAAJAAAAABAAAAkAAAAAEAA5KGAAcAAAASAAAAeKACAAQAAAABAAAAsqAD
AAQAAAABAAAATAAAAABBU0NJSQAAAFNjcmVlbnNob3ReQ+6gAAAACXBIWXMAABYlAAAWJQFJUiTw
AAAB1WlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpu
czptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNi4wLjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9
Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRm
OkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczpleGlmPSJodHRwOi8v
bnMuYWRvYmUuY29tL2V4aWYvMS4wLyI+CiAgICAgICAgIDxleGlmOlBpeGVsWURpbWVuc2lvbj43
NjwvZXhpZjpQaXhlbFlEaW1lbnNpb24+CiAgICAgICAgIDxleGlmOlBpeGVsWERpbWVuc2lvbj4x
Nzg8L2V4aWY6UGl4ZWxYRGltZW5zaW9uPgogICAgICAgICA8ZXhpZjpVc2VyQ29tbWVudD5TY3Jl
ZW5zaG90PC9leGlmOlVzZXJDb21tZW50PgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9y
ZGY6UkRGPgo8L3g6eG1wbWV0YT4KYNB7JQAAABxpRE9UAAAAAgAAAAAAAAAmAAAAKAAAACYAAAAm
AAABBBOG5jIAAADQSURBVHgB7NIBEQAgDAMx5l80cLjgL1Owtpl9bzkNfN7AgPz5gt5/DYAMQqIB
kBMzCgEyA4kGQE7MKATIDCQaADkxoxAgM5BoAOTEjEKAzECiAZATMwoBMgOJBkBOzCgEyAwkGgA5
MaMQIDOQaADkxIxCgMxAogGQEzMKATIDiQZATswoBMgMJBoAOTGjECAzkGgA5MSMQoDMQKIBkBMz
CgEyA4kGQE7MKATIDCQaADkxoxAgM5BoAOTEjEKAzECiAZATMwoBMgOJBkBOzCjEAQAA///X4LVo
AAAAzklEQVTt0gERACAMAzHmXzRwuOAvU7C2mX1vOQ183sCA/PmC3n8NgAxCogGQEzMKATIDiQZA
TswoBMgMJBoAOTGjECAzkGgA5MSMQoDMQKIBkBMzCgEyA4kGQE7MKATIDCQaADkxoxAgM5BoAOTE
jEKAzECiAZATMwoBMgOJBkBOzCgEyAwkGgA5MaMQIDOQaADkxIxCgMxAogGQEzMKATIDiQZATswo
BMgMJBoAOTGjECAzkGgA5MSMQoDMQKIBkBMzCgEyA4kGQE7MKMQBRz8vLLnQPmEAAAAASUVORK5C
YII=

---=Part.16d.b16547c587c987fd.196a380f8d4.b92d6af2f0294389=---
Original file line number Diff line number Diff line change
Expand Up @@ -4828,6 +4828,120 @@ trait EmailGetMethodContract {
|}""".stripMargin)
}

@Test
def inlinedAttachmentMailShouldNotBeCountedAsHasAttachmentWhenEmailFullView(server: GuiceJamesServer): Unit = {
val path = MailboxPath.inbox(BOB)
val mailboxId = server.getProbe(classOf[MailboxProbeImpl]).createMailbox(path)
val messageId: MessageId = server.getProbe(classOf[MailboxProbeImpl])
.appendMessage(BOB.asString, path, AppendCommand.from(
ClassLoaderUtils.getSystemResourceAsSharedStream("eml/simple-inlined-attachment.eml")))
.getMessageId

val request =
s"""{
| "using": [
| "urn:ietf:params:jmap:core",
| "urn:ietf:params:jmap:mail"
| ],
| "methodCalls": [
| [
| "Email/get",
| {
| "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
| "ids": ["${messageId.serialize}"],
| "properties": [
| "id",
| "subject",
| "from",
| "to",
| "cc",
| "bcc",
| "keywords",
| "size",
| "receivedAt",
| "sentAt",
| "preview",
| "hasAttachment",
| "attachments",
| "replyTo",
| "mailboxIds"
| ],
| "fetchTextBodyValues": true
| },
| "c1"
| ]
| ]
|}""".stripMargin
val response = `given`
.header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
.body(request)
.when
.post
.`then`
.statusCode(SC_OK)
.contentType(JSON)
.extract
.body
.asString

assertThatJson(response)
.whenIgnoringPaths("methodResponses[0][1].state")
.isEqualTo(
s"""{
| "sessionState": "${SESSION_STATE.value}",
| "methodResponses": [
| [
| "Email/get",
| {
| "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
| "state": "33ac468f-7903-4f68-ac3e-8120505b5c3d",
| "list": [
| {
| "id": "${messageId.serialize}",
| "keywords": {},
| "mailboxIds": {
| "${mailboxId.serialize}": true
| },
| "size": 7609,
| "receivedAt": "$${json-unit.ignore}",
| "to": [
| {
| "name": "Alice",
| "email": "alice@domain.tld"
| }
| ],
| "from": [
| {
| "name": "Bob",
| "email": "bob@domain.tld"
| }
| ],
| "subject": "inlined attachment",
| "sentAt": "$${json-unit.ignore}",
| "attachments": [
| {
| "partId": "5",
| "blobId": "${messageId.serialize}_5",
| "size": 4334,
| "name": "Screenshot 2025-05-06 at 09.50.27.png",
| "type": "image/png",
| "charset": "base64",
| "disposition": "inline",
| "cid": "e612b3e0-2a24-11f0-aacf-77a69744ec20"
| }
| ],
| "hasAttachment": false,
| "preview": "start[Screenshot 2025-05-06 at 09]end"
| }
| ],
| "notFound": []
| },
| "c1"
| ]
| ]
|}""".stripMargin)
}

@Test
def shouldUseFastViewWithAttachmentMetadataWhenSupportedBodyProperties(server: GuiceJamesServer): Unit = {
val path = MailboxPath.inbox(BOB)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import org.apache.james.jmap.api.projections.{MessageFastViewPrecomputedProperti
import org.apache.james.jmap.core.Id.{Id, IdConstraint}
import org.apache.james.jmap.core.{Properties, UTCDate}
import org.apache.james.jmap.mail.BracketHeader.sanitize
import org.apache.james.jmap.mail.Disposition.ATTACHMENT
import org.apache.james.jmap.mail.EmailFullViewFactory.extractBodyValues
import org.apache.james.jmap.mail.EmailGetRequest.MaxBodyValueBytes
import org.apache.james.jmap.mail.EmailHeaderName.{ADDRESSES_NAMES, DATE, MESSAGE_ID_NAMES}
Expand Down Expand Up @@ -625,7 +626,8 @@ private class EmailFullViewFactory @Inject()(zoneIdProvider: ZoneIdProvider, pre
size = sanitizeSize(firstMessage.getSize)),
header = EmailHeaders.from(zoneIdProvider.get())(mime4JMessage),
bodyMetadata = EmailBodyMetadata(
hasAttachment = HasAttachment(!firstMessage.getLoadedAttachments.isEmpty),
hasAttachment = HasAttachment(bodyStructure.attachments.exists(attachment =>
attachment.disposition.contains(ATTACHMENT) && attachment.cid.isEmpty)),
preview = preview),
body = EmailBody(
bodyStructure = bodyStructure,
Expand Down