From 50d8bbc59df502d748dd646179e58a8220339862 Mon Sep 17 00:00:00 2001 From: M66B Date: Sun, 12 Dec 2021 19:00:58 +0100 Subject: [PATCH] Set resent headers correctly --- FAQ.md | 2 +- .../java/eu/faircode/email/MessageHelper.java | 111 +++++++++++------- .../java/eu/faircode/email/ServiceSend.java | 29 ++++- 3 files changed, 94 insertions(+), 48 deletions(-) diff --git a/FAQ.md b/FAQ.md index 3ac81c4362..7c77cf5ced 100644 --- a/FAQ.md +++ b/FAQ.md @@ -3407,7 +3407,7 @@ Remarks: * The original subject is sent as-is, unless it is being changed * The original message text will be sent as-is, unless text is being entered * The original attachments are sent as they are, unless attachments are being added or removed -* Default CC and BCC addresses will be applied +* Default CC and BCC addresses will not be applied * Read and delivery receipts will be requested when enabled, they could go to the original sender or to you * The email server might refused resent messages * DKIM, SPF and DMARC will likely fail, often causing resent messages to be considered as spam diff --git a/app/src/main/java/eu/faircode/email/MessageHelper.java b/app/src/main/java/eu/faircode/email/MessageHelper.java index 00209f62f1..d5be0e0ef5 100644 --- a/app/src/main/java/eu/faircode/email/MessageHelper.java +++ b/app/src/main/java/eu/faircode/email/MessageHelper.java @@ -281,75 +281,96 @@ public class MessageHelper { MailDateFormat mdf = new MailDateFormat(); mdf.setTimeZone(hide_timezone ? TimeZone.getTimeZone("UTC") : TimeZone.getDefault()); - String date = mdf.format(new Date(message.sent == null ? message.received : message.sent)); - imessage.setHeader("Date", date); + String ourDate = mdf.format(new Date(message.sent == null ? message.received : message.sent)); - Address us = null; - if (message.from != null && message.from.length > 0) { - us = getFrom(message, identity); - imessage.setFrom(us); - } + Address ourFrom = null; + if (message.from != null && message.from.length > 0) + ourFrom = getFrom(message, identity); - // Resend - if (message.headers != null) { + if (message.headers == null) { + imessage.setHeader("Date", ourDate); + + // Addresses + if (ourFrom != null) + imessage.setFrom(ourFrom); + + if (message.to != null && message.to.length > 0) + imessage.setRecipients(Message.RecipientType.TO, convertAddress(message.to, identity)); + + if (message.cc != null && message.cc.length > 0) + imessage.setRecipients(Message.RecipientType.CC, convertAddress(message.cc, identity)); + + if (message.bcc != null && message.bcc.length > 0) + imessage.setRecipients(Message.RecipientType.BCC, convertAddress(message.bcc, identity)); + } else { // https://datatracker.ietf.org/doc/html/rfc2822#section-3.6.6 - if (us != null) - imessage.addHeader("Resent-From", us.toString()); - - imessage.addHeader("Resent-Date", date); - ByteArrayInputStream bis = new ByteArrayInputStream(message.headers.getBytes()); List
headers = Collections.list(new InternetHeaders(bis).getAllHeaders()); + for (Header header : headers) { String name = header.getName(); String value = header.getValue(); - if (name == null || value == null) + if (name == null || TextUtils.isEmpty(value)) continue; switch (name.toLowerCase(Locale.ROOT)) { - case "from": - // Override default header - imessage.setFrom(value); - break; case "date": - // Override default header imessage.setHeader("Date", value); break; - + case "from": + imessage.setFrom(value); + break; case "to": - imessage.addHeader("Resent-To", value); + imessage.setRecipients(Message.RecipientType.TO, InternetAddress.parse(value)); break; case "cc": - imessage.addHeader("Resent-Cc", value); + imessage.setRecipients(Message.RecipientType.CC, InternetAddress.parse(value)); break; case "bcc": - imessage.addHeader("Resent-Bcc", value); + imessage.setRecipients(Message.RecipientType.BCC, InternetAddress.parse(value)); + break; + case "reply-to": + imessage.setReplyTo(InternetAddress.parse(value)); break; // Resent-Sender // Resent-Message-ID } } + // The "Resent-Date:" indicates the date and time at which the resent + // message is dispatched by the resender of the message. + imessage.addHeader("Resent-Date", ourDate); + + // a simple "Resent-From:" form which + // contains the mailbox of the individual doing the resending + if (ourFrom != null) + imessage.addHeader("Resent-From", ourFrom.toString()); + + // The "Resent-To:", "Resent-Cc:", and "Resent-Bcc:" fields function + // identically to the "To:", "Cc:", and "Bcc:" fields respectively, + // except that they indicate the recipients of the resent message, not + // the recipients of the original message. + if (message.to != null && message.to.length > 0) + imessage.addHeader("Resent-To", InternetAddress.toString(message.to)); + + if (message.cc != null && message.cc.length > 0) + imessage.addHeader("Resent-Cc", InternetAddress.toString(message.cc)); + + if (message.bcc != null && message.bcc.length > 0) + imessage.addHeader("Resent-Bcc", InternetAddress.toString(message.bcc)); + + // Each new set of resent fields is prepended to the message; + // that is, the most recent set of resent fields appear earlier in the message. for (Header header : headers) { String name = header.getName(); String value = header.getValue(); - if (name == null || value == null) + if (name == null || TextUtils.isEmpty(value)) continue; if (name.toLowerCase(Locale.ROOT).startsWith("resent-")) imessage.addHeader(name, value); } } - // Addresses - if (message.to != null && message.to.length > 0) - imessage.setRecipients(Message.RecipientType.TO, convertAddress(message.to, identity)); - - if (message.cc != null && message.cc.length > 0) - imessage.setRecipients(Message.RecipientType.CC, convertAddress(message.cc, identity)); - - if (message.bcc != null && message.bcc.length > 0) - imessage.setRecipients(Message.RecipientType.BCC, convertAddress(message.bcc, identity)); - if (message.subject != null) { int maxlen = MAX_HEADER_LENGTH - "Subject: ".length(); if (message.subject.length() > maxlen) @@ -359,17 +380,19 @@ public class MessageHelper { // Send message if (identity != null) { - // Add reply to - if (message.headers == null && identity.replyto != null) - imessage.setReplyTo(convertAddress(InternetAddress.parse(identity.replyto), identity)); + if (message.headers == null) { + // Add reply to + if (identity.replyto != null) + imessage.setReplyTo(convertAddress(InternetAddress.parse(identity.replyto), identity)); - // Add extra cc - if (identity.cc != null) - addAddress(identity.cc, Message.RecipientType.CC, imessage, identity); + // Add extra cc + if (identity.cc != null) + addAddress(identity.cc, Message.RecipientType.CC, imessage, identity); - // Add extra bcc - if (identity.bcc != null) - addAddress(identity.bcc, Message.RecipientType.BCC, imessage, identity); + // Add extra bcc + if (identity.bcc != null) + addAddress(identity.bcc, Message.RecipientType.BCC, imessage, identity); + } // Delivery/read request if (message.receipt_request != null && message.receipt_request) { diff --git a/app/src/main/java/eu/faircode/email/ServiceSend.java b/app/src/main/java/eu/faircode/email/ServiceSend.java index 46603dbc3e..b983042e4a 100644 --- a/app/src/main/java/eu/faircode/email/ServiceSend.java +++ b/app/src/main/java/eu/faircode/email/ServiceSend.java @@ -48,6 +48,8 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -681,9 +683,30 @@ public class ServiceSend extends ServiceBase implements SharedPreferences.OnShar if (ident.max_size == null) max_size = iservice.getMaxSize(); - Address[] to = imessage.getAllRecipients(); + List
recipients = new ArrayList<>(); + if (message.headers == null) { + Address[] all = imessage.getAllRecipients(); + if (all != null) + recipients.addAll(Arrays.asList(all)); + } else { + String to = imessage.getHeader("Resent-To", ","); + if (to != null) + for (Address a : InternetAddress.parse(to)) + recipients.add(a); + + String cc = imessage.getHeader("Resent-Cc", ","); + if (cc != null) + for (Address a : InternetAddress.parse(cc)) + recipients.add(a); + + String bcc = imessage.getHeader("Resent-Bcc", ","); + if (bcc != null) + for (Address a : InternetAddress.parse(bcc)) + recipients.add(a); + } + String via = "via " + ident.host + "/" + ident.user + - " to " + (to == null ? null : TextUtils.join(", ", to)); + " recipients=" + TextUtils.join(", ", recipients); iservice.setReporter(new TraceOutputStream.IReport() { private int progress = -1; @@ -707,7 +730,7 @@ public class ServiceSend extends ServiceBase implements SharedPreferences.OnShar // Send message EntityLog.log(this, "Sending " + via); start = new Date().getTime(); - iservice.getTransport().sendMessage(imessage, to); + iservice.getTransport().sendMessage(imessage, recipients.toArray(new Address[0])); end = new Date().getTime(); EntityLog.log(this, "Sent " + via + " elapse=" + (end - start) + " ms"); } catch (MessagingException ex) {