8 "github.com/mjl-/mox/imapclient"
11func TestFetch(t *testing.T) {
15 tc.client.Login("mjl@mox.example", "testtest")
16 tc.client.Enable("imap4rev2")
17 received, err := time.Parse(time.RFC3339, "2022-11-16T10:01:00+01:00")
18 tc.check(err, "parse time")
19 tc.client.Append("inbox", nil, &received, []byte(exampleMsg))
20 tc.client.Select("inbox")
22 uid1 := imapclient.FetchUID(1)
23 date1 := imapclient.FetchInternalDate("16-Nov-2022 10:01:00 +0100")
24 rfcsize1 := imapclient.FetchRFC822Size(len(exampleMsg))
25 env1 := imapclient.FetchEnvelope{
26 Date: "Mon, 7 Feb 1994 21:52:25 -0800",
27 Subject: "afternoon meeting",
28 From: []imapclient.Address{{Name: "Fred Foobar", Mailbox: "foobar", Host: "blurdybloop.example"}},
29 Sender: []imapclient.Address{{Name: "Fred Foobar", Mailbox: "foobar", Host: "blurdybloop.example"}},
30 ReplyTo: []imapclient.Address{{Name: "Fred Foobar", Mailbox: "foobar", Host: "blurdybloop.example"}},
31 To: []imapclient.Address{{Mailbox: "mooch", Host: "owatagu.siam.edu.example"}},
32 MessageID: "<B27397-0100000@Blurdybloop.example>",
34 noflags := imapclient.FetchFlags(nil)
35 bodyxstructure1 := imapclient.FetchBodystructure{
37 Body: imapclient.BodyTypeText{
39 MediaSubtype: "PLAIN",
40 BodyFields: imapclient.BodyFields{
41 Params: [][2]string{[...]string{"CHARSET", "US-ASCII"}},
47 bodystructure1 := bodyxstructure1
48 bodystructure1.RespAttr = "BODYSTRUCTURE"
50 split := strings.SplitN(exampleMsg, "\r\n\r\n", 2)
51 exampleMsgHeader := split[0] + "\r\n\r\n"
52 exampleMsgBody := split[1]
54 binary1 := imapclient.FetchBinary{RespAttr: "BINARY[]", Data: exampleMsg}
55 binarypart1 := imapclient.FetchBinary{RespAttr: "BINARY[1]", Parts: []uint32{1}, Data: exampleMsgBody}
56 binarypartial1 := imapclient.FetchBinary{RespAttr: "BINARY[]", Data: exampleMsg[1:2]}
57 binarypartpartial1 := imapclient.FetchBinary{RespAttr: "BINARY[1]", Parts: []uint32{1}, Data: exampleMsgBody[1:2]}
58 binaryend1 := imapclient.FetchBinary{RespAttr: "BINARY[]", Data: ""}
59 binarypartend1 := imapclient.FetchBinary{RespAttr: "BINARY[1]", Parts: []uint32{1}, Data: ""}
60 binarysize1 := imapclient.FetchBinarySize{RespAttr: "BINARY.SIZE[]", Size: int64(len(exampleMsg))}
61 binarysizepart1 := imapclient.FetchBinarySize{RespAttr: "BINARY.SIZE[1]", Parts: []uint32{1}, Size: int64(len(exampleMsgBody))}
62 bodyheader1 := imapclient.FetchBody{RespAttr: "BODY[HEADER]", Section: "HEADER", Body: exampleMsgHeader}
63 bodytext1 := imapclient.FetchBody{RespAttr: "BODY[TEXT]", Section: "TEXT", Body: exampleMsgBody}
64 body1 := imapclient.FetchBody{RespAttr: "BODY[]", Body: exampleMsg}
65 bodypart1 := imapclient.FetchBody{RespAttr: "BODY[1]", Section: "1", Body: exampleMsgBody}
66 bodyoff1 := imapclient.FetchBody{RespAttr: "BODY[]<1>", Section: "", Offset: 1, Body: exampleMsg[1:3]}
67 body1off1 := imapclient.FetchBody{RespAttr: "BODY[1]<1>", Section: "1", Offset: 1, Body: exampleMsgBody[1:3]}
68 bodyend1 := imapclient.FetchBody{RespAttr: "BODY[1]<100000>", Section: "1", Offset: 100000, Body: ""} // todo: should offset be what was requested, or the size of the message?
69 rfcheader1 := imapclient.FetchRFC822Header(exampleMsgHeader)
70 rfctext1 := imapclient.FetchRFC822Text(exampleMsgBody)
71 rfc1 := imapclient.FetchRFC822(exampleMsg)
72 headerSplit := strings.SplitN(exampleMsgHeader, "\r\n", 2)
73 dateheader1 := imapclient.FetchBody{RespAttr: "BODY[HEADER.FIELDS (Date)]", Section: "HEADER.FIELDS (Date)", Body: headerSplit[0] + "\r\n\r\n"}
74 nodateheader1 := imapclient.FetchBody{RespAttr: "BODY[HEADER.FIELDS.NOT (Date)]", Section: "HEADER.FIELDS.NOT (Date)", Body: headerSplit[1]}
75 date1header1 := imapclient.FetchBody{RespAttr: "BODY[1.HEADER.FIELDS (Date)]", Section: "1.HEADER.FIELDS (Date)", Body: headerSplit[0] + "\r\n\r\n"}
76 nodate1header1 := imapclient.FetchBody{RespAttr: "BODY[1.HEADER.FIELDS.NOT (Date)]", Section: "1.HEADER.FIELDS.NOT (Date)", Body: headerSplit[1]}
77 mime1 := imapclient.FetchBody{RespAttr: "BODY[1.MIME]", Section: "1.MIME", Body: "MIME-Version: 1.0\r\nContent-Type: TEXT/PLAIN; CHARSET=US-ASCII\r\n\r\n"}
79 flagsSeen := imapclient.FetchFlags{`\Seen`}
81 tc.transactf("ok", "fetch 1 all")
82 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, date1, rfcsize1, env1, noflags}})
84 tc.transactf("ok", "fetch 1 fast")
85 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, date1, rfcsize1, noflags}})
87 tc.transactf("ok", "fetch 1 full")
88 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, date1, rfcsize1, env1, bodyxstructure1, noflags}})
90 tc.transactf("ok", "fetch 1 flags")
91 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, noflags}})
93 tc.transactf("ok", "fetch 1 bodystructure")
94 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, bodystructure1}})
96 // Should be returned unmodified, because there is no content-transfer-encoding.
97 tc.transactf("ok", "fetch 1 binary[]")
98 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, binary1, flagsSeen}})
100 tc.transactf("ok", "fetch 1 binary[1]")
101 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, binarypart1}}) // Seen flag not changed.
103 tc.client.StoreFlagsClear("1", true, `\Seen`)
104 tc.transactf("ok", "fetch 1 binary[]<1.1>")
105 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, binarypartial1, flagsSeen}})
107 tc.client.StoreFlagsClear("1", true, `\Seen`)
108 tc.transactf("ok", "fetch 1 binary[1]<1.1>")
109 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, binarypartpartial1, flagsSeen}})
111 tc.client.StoreFlagsClear("1", true, `\Seen`)
112 tc.transactf("ok", "fetch 1 binary[]<10000.10001>")
113 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, binaryend1, flagsSeen}})
115 tc.client.StoreFlagsClear("1", true, `\Seen`)
116 tc.transactf("ok", "fetch 1 binary[1]<10000.10001>")
117 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, binarypartend1, flagsSeen}})
119 tc.client.StoreFlagsClear("1", true, `\Seen`)
120 tc.transactf("ok", "fetch 1 binary.size[]")
121 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, binarysize1}})
123 tc.transactf("ok", "fetch 1 binary.size[1]")
124 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, binarysizepart1}})
126 tc.client.StoreFlagsClear("1", true, `\Seen`)
127 tc.transactf("ok", "fetch 1 body[]")
128 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, body1, flagsSeen}})
129 tc.transactf("ok", "fetch 1 body[]<1.2>")
130 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, bodyoff1}}) // Already seen.
132 tc.client.StoreFlagsClear("1", true, `\Seen`)
133 tc.transactf("ok", "fetch 1 body[1]")
134 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, bodypart1, flagsSeen}})
136 tc.client.StoreFlagsClear("1", true, `\Seen`)
137 tc.transactf("ok", "fetch 1 body[1]<1.2>")
138 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, body1off1, flagsSeen}})
140 tc.client.StoreFlagsClear("1", true, `\Seen`)
141 tc.transactf("ok", "fetch 1 body[1]<100000.100000>")
142 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, bodyend1, flagsSeen}})
144 tc.client.StoreFlagsClear("1", true, `\Seen`)
145 tc.transactf("ok", "fetch 1 body[header]")
146 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, bodyheader1, flagsSeen}})
148 tc.client.StoreFlagsClear("1", true, `\Seen`)
149 tc.transactf("ok", "fetch 1 body[text]")
150 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, bodytext1, flagsSeen}})
153 tc.client.StoreFlagsClear("1", true, `\Seen`)
154 tc.transactf("ok", "fetch 1 rfc822.header")
155 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, rfcheader1}})
158 tc.client.StoreFlagsClear("1", true, `\Seen`)
159 tc.transactf("ok", "fetch 1 rfc822.text")
160 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, rfctext1, flagsSeen}})
163 tc.client.StoreFlagsClear("1", true, `\Seen`)
164 tc.transactf("ok", "fetch 1 rfc822")
165 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, rfc1, flagsSeen}})
167 // With PEEK, we should not get the \Seen flag.
168 tc.client.StoreFlagsClear("1", true, `\Seen`)
169 tc.transactf("ok", "fetch 1 body.peek[]")
170 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, body1}})
172 tc.transactf("ok", "fetch 1 binary.peek[]")
173 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, binary1}})
175 // HEADER.FIELDS and .NOT
176 tc.transactf("ok", "fetch 1 body.peek[header.fields (date)]")
177 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, dateheader1}})
178 tc.transactf("ok", "fetch 1 body.peek[header.fields.not (date)]")
179 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, nodateheader1}})
181 tc.transactf("ok", "fetch 1 body.peek[1.header.fields (date)]")
182 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, date1header1}})
183 tc.transactf("ok", "fetch 1 body.peek[1.header.fields.not (date)]")
184 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, nodate1header1}})
187 tc.transactf("ok", "fetch 1 body.peek[1.mime]")
188 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, mime1}})
191 tc.transactf("bad", "fetch 2 body[]")
193 tc.transactf("ok", "fetch 1:1 body[]")
194 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, body1, flagsSeen}})
197 tc.transactf("ok", "uid fetch 1 body[]")
198 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, body1}})
201 tc.transactf("ok", "uid fetch 2 body[]")
204 // Test some invalid syntax.
205 tc.transactf("bad", "fetch")
206 tc.transactf("bad", "fetch ")
207 tc.transactf("bad", "fetch ")
208 tc.transactf("bad", "fetch 1") // At least one requested item required.
209 tc.transactf("bad", "fetch 1 ()") // Empty list not allowed
210 tc.transactf("bad", "fetch 1 unknown")
211 tc.transactf("bad", "fetch 1 (unknown)")
212 tc.transactf("bad", "fetch 1 (all)") // Macro's not allowed in list.
213 tc.transactf("bad", "fetch 1 binary") // [] required
214 tc.transactf("bad", "fetch 1 binary[text]") // Text/header etc only allowed for body[].
215 tc.transactf("bad", "fetch 1 binary[]<1>") // Count required.
216 tc.transactf("bad", "fetch 1 binary[]<1.0>") // Count must be > 0.
217 tc.transactf("bad", "fetch 1 binary[]<1..1>") // Single dot.
218 tc.transactf("bad", "fetch 1 body[]<1>") // Count required.
219 tc.transactf("bad", "fetch 1 body[]<1.0>") // Count must be > 0.
220 tc.transactf("bad", "fetch 1 body[]<1..1>") // Single dot.
221 tc.transactf("bad", "fetch 1 body[header.fields]") // List of headers required.
222 tc.transactf("bad", "fetch 1 body[header.fields ()]") // List must be non-empty.
223 tc.transactf("bad", "fetch 1 body[header.fields.not]") // List of headers required.
224 tc.transactf("bad", "fetch 1 body[header.fields.not ()]") // List must be non-empty.
225 tc.transactf("bad", "fetch 1 body[mime]") // MIME must be prefixed with a number.
../rfc/9051:4497
227 tc.transactf("no", "fetch 1 body[2]") // No such part.
229 // Add more complex message.
231 uid2 := imapclient.FetchUID(2)
232 bodystructure2 := imapclient.FetchBodystructure{
233 RespAttr: "BODYSTRUCTURE",
234 Body: imapclient.BodyTypeMpart{
236 imapclient.BodyTypeBasic{BodyFields: imapclient.BodyFields{Octets: 275}},
237 imapclient.BodyTypeText{MediaType: "TEXT", MediaSubtype: "PLAIN", BodyFields: imapclient.BodyFields{Params: [][2]string{{"CHARSET", "US-ASCII"}}, Octets: 114}, Lines: 3},
238 imapclient.BodyTypeMpart{
240 imapclient.BodyTypeBasic{MediaType: "AUDIO", MediaSubtype: "BASIC", BodyFields: imapclient.BodyFields{CTE: "BASE64", Octets: 22}},
241 imapclient.BodyTypeBasic{MediaType: "IMAGE", MediaSubtype: "JPEG", BodyFields: imapclient.BodyFields{CTE: "BASE64"}},
243 MediaSubtype: "PARALLEL",
245 imapclient.BodyTypeText{MediaType: "TEXT", MediaSubtype: "ENRICHED", BodyFields: imapclient.BodyFields{Octets: 145}, Lines: 5},
246 imapclient.BodyTypeMsg{
247 MediaType: "MESSAGE",
248 MediaSubtype: "RFC822",
249 BodyFields: imapclient.BodyFields{Octets: 228},
250 Envelope: imapclient.Envelope{
251 Subject: "(subject in US-ASCII)",
252 From: []imapclient.Address{{Name: "", Adl: "", Mailbox: "info", Host: "mox.example"}},
253 Sender: []imapclient.Address{{Name: "", Adl: "", Mailbox: "info", Host: "mox.example"}},
254 ReplyTo: []imapclient.Address{{Name: "", Adl: "", Mailbox: "info", Host: "mox.example"}},
255 To: []imapclient.Address{{Name: "mox", Adl: "", Mailbox: "info", Host: "mox.example"}},
257 Bodystructure: imapclient.BodyTypeText{
258 MediaType: "TEXT", MediaSubtype: "PLAIN", BodyFields: imapclient.BodyFields{Params: [][2]string{{"CHARSET", "ISO-8859-1"}}, CTE: "QUOTED-PRINTABLE", Octets: 51}, Lines: 1},
262 MediaSubtype: "MIXED",
265 tc.client.Append("inbox", nil, &received, []byte(nestedMessage))
266 tc.transactf("ok", "fetch 2 bodystructure")
267 tc.xuntagged(imapclient.UntaggedFetch{Seq: 2, Attrs: []imapclient.FetchAttr{uid2, bodystructure2}})
269 // Multiple responses.
270 tc.transactf("ok", "fetch 1:2 bodystructure")
271 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, bodystructure1}}, imapclient.UntaggedFetch{Seq: 2, Attrs: []imapclient.FetchAttr{uid2, bodystructure2}})
272 tc.transactf("ok", "fetch 1,2 bodystructure")
273 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, bodystructure1}}, imapclient.UntaggedFetch{Seq: 2, Attrs: []imapclient.FetchAttr{uid2, bodystructure2}})
274 tc.transactf("ok", "fetch 2:1 bodystructure")
275 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, bodystructure1}}, imapclient.UntaggedFetch{Seq: 2, Attrs: []imapclient.FetchAttr{uid2, bodystructure2}})
276 tc.transactf("ok", "fetch 1:* bodystructure")
277 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, bodystructure1}}, imapclient.UntaggedFetch{Seq: 2, Attrs: []imapclient.FetchAttr{uid2, bodystructure2}})
278 tc.transactf("ok", "fetch *:1 bodystructure")
279 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, bodystructure1}}, imapclient.UntaggedFetch{Seq: 2, Attrs: []imapclient.FetchAttr{uid2, bodystructure2}})
280 tc.transactf("ok", "fetch *:2 bodystructure")
281 tc.xuntagged(imapclient.UntaggedFetch{Seq: 2, Attrs: []imapclient.FetchAttr{uid2, bodystructure2}})
283 tc.transactf("ok", "fetch * bodystructure") // Highest msgseq.
284 tc.xuntagged(imapclient.UntaggedFetch{Seq: 2, Attrs: []imapclient.FetchAttr{uid2, bodystructure2}})
286 tc.transactf("ok", "uid fetch 1:* bodystructure")
287 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, bodystructure1}}, imapclient.UntaggedFetch{Seq: 2, Attrs: []imapclient.FetchAttr{uid2, bodystructure2}})
289 tc.transactf("ok", "uid fetch 1:2 bodystructure")
290 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, bodystructure1}}, imapclient.UntaggedFetch{Seq: 2, Attrs: []imapclient.FetchAttr{uid2, bodystructure2}})
292 tc.transactf("ok", "uid fetch 1,2 bodystructure")
293 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, bodystructure1}}, imapclient.UntaggedFetch{Seq: 2, Attrs: []imapclient.FetchAttr{uid2, bodystructure2}})
295 tc.transactf("ok", "uid fetch 2:2 bodystructure")
296 tc.xuntagged(imapclient.UntaggedFetch{Seq: 2, Attrs: []imapclient.FetchAttr{uid2, bodystructure2}})
298 // todo: read the bodies/headers of the parts, and of the nested message.
299 tc.transactf("ok", "fetch 2 body.peek[]")
300 tc.xuntagged(imapclient.UntaggedFetch{Seq: 2, Attrs: []imapclient.FetchAttr{uid2, imapclient.FetchBody{RespAttr: "BODY[]", Body: nestedMessage}}})
302 part1 := tocrlf(` ... Some text appears here ...
304[Note that the blank between the boundary and the start
305 of the text in this part means no header fields were
306 given and this is text in the US-ASCII character set.
307 It could have been done with explicit typing as in the
310 tc.transactf("ok", "fetch 2 body.peek[1]")
311 tc.xuntagged(imapclient.UntaggedFetch{Seq: 2, Attrs: []imapclient.FetchAttr{uid2, imapclient.FetchBody{RespAttr: "BODY[1]", Section: "1", Body: part1}}})
313 tc.transactf("no", "fetch 2 binary.peek[3]") // Only allowed on leaf parts, not multiparts.
314 tc.transactf("no", "fetch 2 binary.peek[5]") // Only allowed on leaf parts, not messages.
316 part31 := "aGVsbG8NCndvcmxkDQo=\r\n"
317 part31dec := "hello\r\nworld\r\n"
318 tc.transactf("ok", "fetch 2 binary.size[3.1]")
319 tc.xuntagged(imapclient.UntaggedFetch{Seq: 2, Attrs: []imapclient.FetchAttr{uid2, imapclient.FetchBinarySize{RespAttr: "BINARY.SIZE[3.1]", Parts: []uint32{3, 1}, Size: int64(len(part31dec))}}})
321 tc.transactf("ok", "fetch 2 body.peek[3.1]")
322 tc.xuntagged(imapclient.UntaggedFetch{Seq: 2, Attrs: []imapclient.FetchAttr{uid2, imapclient.FetchBody{RespAttr: "BODY[3.1]", Section: "3.1", Body: part31}}})
324 tc.transactf("ok", "fetch 2 binary.peek[3.1]")
325 tc.xuntagged(imapclient.UntaggedFetch{Seq: 2, Attrs: []imapclient.FetchAttr{uid2, imapclient.FetchBinary{RespAttr: "BINARY[3.1]", Parts: []uint32{3, 1}, Data: part31dec}}})
327 part3 := tocrlf(`--unique-boundary-2
328Content-Type: audio/basic
329Content-Transfer-Encoding: base64
334Content-Type: image/jpeg
335Content-Transfer-Encoding: base64
341 tc.transactf("ok", "fetch 2 body.peek[3]")
342 tc.xuntagged(imapclient.UntaggedFetch{Seq: 2, Attrs: []imapclient.FetchAttr{uid2, imapclient.FetchBody{RespAttr: "BODY[3]", Section: "3", Body: part3}}})
344 part2mime := tocrlf(`Content-type: text/plain; charset=US-ASCII
347 tc.transactf("ok", "fetch 2 body.peek[2.mime]")
348 tc.xuntagged(imapclient.UntaggedFetch{Seq: 2, Attrs: []imapclient.FetchAttr{uid2, imapclient.FetchBody{RespAttr: "BODY[2.MIME]", Section: "2.MIME", Body: part2mime}}})
350 part5 := tocrlf(`From: info@mox.example
351To: mox <info@mox.example>
352Subject: (subject in US-ASCII)
353Content-Type: Text/plain; charset=ISO-8859-1
354Content-Transfer-Encoding: Quoted-printable
356 ... Additional text in ISO-8859-1 goes here ...
358 tc.transactf("ok", "fetch 2 body.peek[5]")
359 tc.xuntagged(imapclient.UntaggedFetch{Seq: 2, Attrs: []imapclient.FetchAttr{uid2, imapclient.FetchBody{RespAttr: "BODY[5]", Section: "5", Body: part5}}})
361 part5header := tocrlf(`From: info@mox.example
362To: mox <info@mox.example>
363Subject: (subject in US-ASCII)
364Content-Type: Text/plain; charset=ISO-8859-1
365Content-Transfer-Encoding: Quoted-printable
368 tc.transactf("ok", "fetch 2 body.peek[5.header]")
369 tc.xuntagged(imapclient.UntaggedFetch{Seq: 2, Attrs: []imapclient.FetchAttr{uid2, imapclient.FetchBody{RespAttr: "BODY[5.HEADER]", Section: "5.HEADER", Body: part5header}}})
371 part5mime := tocrlf(`Content-Type: Text/plain; charset=ISO-8859-1
372Content-Transfer-Encoding: Quoted-printable
375 tc.transactf("ok", "fetch 2 body.peek[5.mime]")
376 tc.xuntagged(imapclient.UntaggedFetch{Seq: 2, Attrs: []imapclient.FetchAttr{uid2, imapclient.FetchBody{RespAttr: "BODY[5.MIME]", Section: "5.MIME", Body: part5mime}}})
378 part5text := " ... Additional text in ISO-8859-1 goes here ...\r\n"
379 tc.transactf("ok", "fetch 2 body.peek[5.text]")
380 tc.xuntagged(imapclient.UntaggedFetch{Seq: 2, Attrs: []imapclient.FetchAttr{uid2, imapclient.FetchBody{RespAttr: "BODY[5.TEXT]", Section: "5.TEXT", Body: part5text}}})
382 tc.transactf("ok", "fetch 2 body.peek[5.1]")
383 tc.xuntagged(imapclient.UntaggedFetch{Seq: 2, Attrs: []imapclient.FetchAttr{uid2, imapclient.FetchBody{RespAttr: "BODY[5.1]", Section: "5.1", Body: part5text}}})
385 // In case of EXAMINE instead of SELECT, we should not be seeing any changed \Seen flags for non-peek commands.
386 tc.client.StoreFlagsClear("1", true, `\Seen`)
388 tc.client.Examine("inbox")
390 tc.transactf("ok", "fetch 1 binary[]")
391 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, binary1}})
393 tc.transactf("ok", "fetch 1 body[]")
394 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, body1}})
396 tc.transactf("ok", "fetch 1 rfc822.text")
397 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, rfctext1}})
399 tc.transactf("ok", "fetch 1 rfc822")
400 tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, rfc1}})