@@ -112,7 +112,84 @@ fn main() {
112
112
} ,
113
113
OriginalMessageBody :: Error ( _) => None ,
114
114
} ;
115
- tracing:: debug!( could_parse = original_parsed. is_some( ) , "parsed message" ) ;
115
+ tracing:: debug!(
116
+ could_parse = original_parsed. is_some( ) ,
117
+ ?original_parsed,
118
+ "parsed message"
119
+ ) ;
120
+
121
+ // Try to create an inline attachment for the receivers's convenience of not
122
+ // having to double-click the attachment.
123
+ //
124
+ // This is surprisingly tricky, as the message/rfc822 MIME type only allows
125
+ // Content-Transfer-Encoding 7bit, 8bit or binary.
126
+ // Any other encoding (quoted-printable, base64) will break in
127
+ // Gmail and AppleMail, probably elsewhere. The exact kind of breakage depends:
128
+ // in AppleMail, only the `From`, `To`, and `Subject`
129
+ // headers are shown inline, and the rest of the message is not visible / accessible.
130
+ // In Gmail, it always shows as an attachment and one gets an error when clicking on it.
131
+ let re_encoded = ( || {
132
+ let Some ( original_parsed) = & original_parsed else {
133
+ debug ! ( "not parseable" ) ;
134
+ return None ;
135
+ } ;
136
+ if original_parsed. ctype . mimetype != "text/plain" {
137
+ // TODO: implement support.
138
+ // Multi-part would be tricky as we'd possible need to use different
139
+ // boundaries to avoid collisions with the boundaries that our wrapper
140
+ // message will add.
141
+ debug ! ( "not text/plain content-type" ) ;
142
+ return None ;
143
+ }
144
+ let mut builder = SinglePart :: builder ( ) ;
145
+ for header in & original_parsed. headers {
146
+ #[ derive( Clone ) ]
147
+ struct RawHeader ( HeaderName , String ) ;
148
+ impl lettre:: message:: header:: Header for RawHeader {
149
+ fn name ( ) -> HeaderName {
150
+ unimplemented ! ( "not needed, we only use display" )
151
+ }
152
+
153
+ fn parse ( _: & str ) -> Result < Self , Box < dyn std:: error:: Error + Send + Sync > > {
154
+ unimplemented ! ( "not needed, we only use display" )
155
+ }
156
+
157
+ fn display ( & self ) -> lettre:: message:: header:: HeaderValue {
158
+ HeaderValue :: new ( self . 0 . clone ( ) , self . 1 . clone ( ) )
159
+ }
160
+ }
161
+ impl RawHeader {
162
+ fn new ( hdr : & mailparse:: MailHeader ) -> Option < Self > {
163
+ let header_name =
164
+ HeaderName :: new_from_ascii ( hdr. get_key ( ) ) . ok ( ) . or_else ( || {
165
+ debug ! ( hdr=?hdr. get_key( ) , "header is not ascii" ) ;
166
+ None
167
+ } ) ?;
168
+ let header_value = hdr. get_value_utf8 ( ) . ok ( ) . or_else ( || {
169
+ debug ! ( hdr=?hdr, "header value is not utf-8" ) ;
170
+ None
171
+ } ) ?;
172
+ Some ( Self ( header_name, header_value) )
173
+ }
174
+ }
175
+ builder = builder. header ( RawHeader :: new ( header) . or_else ( || {
176
+ debug ! ( "can't adapt libraries into each other" ) ;
177
+ None
178
+ } ) ?) ;
179
+ }
180
+ Some (
181
+ builder. body (
182
+ Body :: new_with_encoding (
183
+ original_parsed. get_body ( ) . ok ( ) . or_else ( || {
184
+ debug ! ( "cannot get body" ) ;
185
+ None
186
+ } ) ?,
187
+ lettre:: message:: header:: ContentTransferEncoding :: Base64 ,
188
+ )
189
+ . unwrap ( ) ,
190
+ ) ,
191
+ )
192
+ } ) ( ) ;
116
193
117
194
// Put together the wrapper message
118
195
let sender = {
@@ -209,10 +286,14 @@ fn main() {
209
286
writeln ! ( & mut body, "WARNING: could not determine permissions of the config file, they may or may not be too lax: {e}" ) ?;
210
287
} ,
211
288
}
212
- writeln ! (
213
- & mut body,
214
- "The original message is attached inline to this wrapper message."
215
- ) ?;
289
+ writeln ! ( & mut body) ?;
290
+ {
291
+ write ! ( & mut body, "The original message is attached to this wrapper message." ) ?;
292
+ if re_encoded. is_some ( ) {
293
+ write ! ( & mut body, " For convenience, a re-encoded copy is attached inline." ) ?;
294
+ }
295
+ writeln ! ( & mut body) ?;
296
+ }
216
297
writeln ! ( & mut body) ?;
217
298
writeln ! ( & mut body, "Invocation args: {args}" ) ?;
218
299
writeln ! ( & mut body) ?;
@@ -261,83 +342,7 @@ fn main() {
261
342
. multipart ( {
262
343
let mut mp_builder = MultiPart :: mixed ( ) . singlepart ( SinglePart :: plain ( body) ) ;
263
344
264
- // Try to create an inline attachment for the receivers's convenience of not
265
- // having to double-click the attachment.
266
- //
267
- // This is surprisingly tricky, as the message/rfc822 MIME type only allows
268
- // Content-Transfer-Encoding 7bit, 8bit or binary.
269
- // Any other encoding (quoted-printable, base64) will break in
270
- // Gmail and AppleMail, probably elsewhere. The exact kind of breakage depends:
271
- // in AppleMail, only the `From`, `To`, and `Subject`
272
- // headers are shown inline, and the rest of the message is not visible / accessible.
273
- // In Gmail, it always shows as an attachment and one gets an error when clicking on it.
274
- //
275
- // So, try to re-encode the message body. If that doesn't work, the user can fallback
276
- // to the attachment.
277
345
mp_builder = {
278
- let re_encoded = ( || {
279
- let Some ( original_parsed) = original_parsed else {
280
- debug ! ( "not parseable" ) ;
281
- return None ;
282
- } ;
283
- if original_parsed. ctype . mimetype != "text/plain" {
284
- debug ! ( "not text/plain content-type" ) ;
285
- return None ;
286
- }
287
- let mut builder = SinglePart :: builder ( ) ;
288
- for header in & original_parsed. headers {
289
- #[ derive( Clone ) ]
290
- struct RawHeader ( HeaderName , String ) ;
291
- impl lettre:: message:: header:: Header for RawHeader {
292
- fn name ( ) -> HeaderName {
293
- unimplemented ! ( "not needed, we only use display" )
294
- }
295
-
296
- fn parse (
297
- _: & str ,
298
- ) -> Result < Self , Box < dyn std:: error:: Error + Send + Sync > >
299
- {
300
- unimplemented ! ( "not needed, we only use display" )
301
- }
302
-
303
- fn display ( & self ) -> lettre:: message:: header:: HeaderValue {
304
- HeaderValue :: new ( self . 0 . clone ( ) , self . 1 . clone ( ) )
305
- }
306
- }
307
- impl RawHeader {
308
- fn new ( hdr : & mailparse:: MailHeader ) -> Option < Self > {
309
- let header_name = HeaderName :: new_from_ascii ( hdr. get_key ( ) )
310
- . ok ( )
311
- . or_else ( || {
312
- debug ! ( hdr=?hdr. get_key( ) , "header is not ascii" ) ;
313
- None
314
- } ) ?;
315
- let header_value = hdr. get_value_utf8 ( ) . ok ( ) . or_else ( || {
316
- debug ! ( hdr=?hdr, "header value is not utf-8" ) ;
317
- None
318
- } ) ?;
319
- Some ( Self ( header_name, header_value) )
320
- }
321
- }
322
- builder = builder. header ( RawHeader :: new ( header) . or_else ( || {
323
- debug ! ( "can't adapt libraries into each other" ) ;
324
- None
325
- } ) ?) ;
326
- }
327
- Some (
328
- builder. body (
329
- Body :: new_with_encoding (
330
- original_parsed. get_body ( ) . ok ( ) . or_else ( || {
331
- debug ! ( "cannot get body" ) ;
332
- None
333
- } ) ?,
334
- lettre:: message:: header:: ContentTransferEncoding :: Base64 ,
335
- )
336
- . unwrap ( ) ,
337
- ) ,
338
- )
339
- } ) ( ) ;
340
-
341
346
if let Some ( re_encoded) = re_encoded {
342
347
mp_builder. singlepart (
343
348
SinglePart :: builder ( )
0 commit comments