70 match -> match.group(2)
71 .replaceAll("\\R", "")));
72 ret.headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
73 ret.headers.putAll(headers);
74 ret.body = parts[1].stripTrailing();
75 return ret;
76 }
77
78 private static final Pattern redundantTimeZonePattern = Pattern.compile("^(.*[-+\\d{4}]) \\(\\w+\\)$");
79
80 public static Email parse(String raw) {
81 var message = parseMboxMessage(raw);
82
83 var id = EmailAddress.parse(message.headers.get("Message-Id"));
84 var unparsedDate = message.headers.get("Date");
85 var redundantTimeZonePatternMatcher = redundantTimeZonePattern.matcher(unparsedDate);
86 if (redundantTimeZonePatternMatcher.matches()) {
87 unparsedDate = redundantTimeZonePatternMatcher.group(1);
88 }
89 var date = ZonedDateTime.parse(unparsedDate, DateTimeFormatter.RFC_1123_DATE_TIME);
90 var subject = message.headers.get("Subject");
91 var author = EmailAddress.parse(message.headers.get("From"));
92 var sender = author;
93 if (message.headers.containsKey("Sender")) {
94 sender = EmailAddress.parse(message.headers.get("Sender"));
95 }
96 List<EmailAddress> recipients;
97 if (message.headers.containsKey("To")) {
98 recipients = Arrays.stream(message.headers.get("To").split(","))
99 .map(EmailAddress::parse)
100 .collect(Collectors.toList());
101 } else {
102 recipients = List.of();
103 }
104
105 // Remove all known headers
106 var filteredHeaders = message.headers.entrySet().stream()
107 .filter(entry -> !entry.getKey().equalsIgnoreCase("Message-Id"))
108 .filter(entry -> !entry.getKey().equalsIgnoreCase("Date"))
109 .filter(entry -> !entry.getKey().equalsIgnoreCase("Subject"))
110 .filter(entry -> !entry.getKey().equalsIgnoreCase("From"))
111 .filter(entry -> !entry.getKey().equalsIgnoreCase("Sender"))
112 .filter(entry -> !entry.getKey().equalsIgnoreCase("To"))
113 .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
114
115 return new Email(id, date, recipients, author, sender, subject, message.body, filteredHeaders);
116 }
117
118 public static EmailBuilder create(EmailAddress author, String subject, String body) {
119 return new EmailBuilder(author, subject, body);
120 }
121
122 public static EmailBuilder create(String subject, String body) {
123 return new EmailBuilder(subject, body);
124 }
125
126 public static EmailBuilder from(Email email) {
127 return new EmailBuilder(email.author, email.subject, email.body)
128 .sender(email.sender)
129 .recipients(email.recipients)
130 .id(email.id)
131 .date(email.date)
132 .headers(email.headers);
133 }
134
135 public static EmailBuilder reply(Email parent, String subject, String body) {
|
70 match -> match.group(2)
71 .replaceAll("\\R", "")));
72 ret.headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
73 ret.headers.putAll(headers);
74 ret.body = parts[1].stripTrailing();
75 return ret;
76 }
77
78 private static final Pattern redundantTimeZonePattern = Pattern.compile("^(.*[-+\\d{4}]) \\(\\w+\\)$");
79
80 public static Email parse(String raw) {
81 var message = parseMboxMessage(raw);
82
83 var id = EmailAddress.parse(message.headers.get("Message-Id"));
84 var unparsedDate = message.headers.get("Date");
85 var redundantTimeZonePatternMatcher = redundantTimeZonePattern.matcher(unparsedDate);
86 if (redundantTimeZonePatternMatcher.matches()) {
87 unparsedDate = redundantTimeZonePatternMatcher.group(1);
88 }
89 var date = ZonedDateTime.parse(unparsedDate, DateTimeFormatter.RFC_1123_DATE_TIME);
90 var subject = MimeText.decode(message.headers.get("Subject"));
91 var author = EmailAddress.parse(MimeText.decode(message.headers.get("From")));
92 var sender = author;
93 if (message.headers.containsKey("Sender")) {
94 sender = EmailAddress.parse(MimeText.decode(message.headers.get("Sender")));
95 }
96 List<EmailAddress> recipients;
97 if (message.headers.containsKey("To")) {
98 recipients = Arrays.stream(message.headers.get("To").split(","))
99 .map(MimeText::decode)
100 .map(EmailAddress::parse)
101 .collect(Collectors.toList());
102 } else {
103 recipients = List.of();
104 }
105
106 // Remove all known headers
107 var filteredHeaders = message.headers.entrySet().stream()
108 .filter(entry -> !entry.getKey().equalsIgnoreCase("Message-Id"))
109 .filter(entry -> !entry.getKey().equalsIgnoreCase("Date"))
110 .filter(entry -> !entry.getKey().equalsIgnoreCase("Subject"))
111 .filter(entry -> !entry.getKey().equalsIgnoreCase("From"))
112 .filter(entry -> !entry.getKey().equalsIgnoreCase("Sender"))
113 .filter(entry -> !entry.getKey().equalsIgnoreCase("To"))
114 .collect(Collectors.toMap(Map.Entry::getKey,
115 entry -> MimeText.decode(entry.getValue())));
116
117 return new Email(id, date, recipients, author, sender, subject, MimeText.decode(message.body), filteredHeaders);
118 }
119
120 public static EmailBuilder create(EmailAddress author, String subject, String body) {
121 return new EmailBuilder(author, subject, body);
122 }
123
124 public static EmailBuilder create(String subject, String body) {
125 return new EmailBuilder(subject, body);
126 }
127
128 public static EmailBuilder from(Email email) {
129 return new EmailBuilder(email.author, email.subject, email.body)
130 .sender(email.sender)
131 .recipients(email.recipients)
132 .id(email.id)
133 .date(email.date)
134 .headers(email.headers);
135 }
136
137 public static EmailBuilder reply(Email parent, String subject, String body) {
|