@@ -17,6 +17,11 @@ final _lenientEmailRegExp = RegExp(r'^\S+@\S+\.\S+$');
17
17
final _strictEmailRegExp = RegExp (
18
18
r'''[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$''' );
19
19
20
+ /// Matches the local part of the email's message-id field, with relaxed rules:
21
+ /// - checks that only valid characters are present
22
+ /// - checks for minimum and maximum length
23
+ final _messageIdLocalPartRegExp = RegExp (r'^[0-9a-zA-Z\-]{19,36}$' );
24
+
20
25
final _invitesFrom = EmailAddress (
21
26
_invitesAtPubDev,
22
27
name: 'Dart package site invites' ,
@@ -100,9 +105,15 @@ class EmailMessage {
100
105
///
101
106
/// [localMessageId] is not required while in the message construction phase,
102
107
/// but a must have when sending out the actual email. `EmailSender`
103
- /// implementation must call [verifyLocalMessageId ] before accepting the email
108
+ /// implementation must call [verifyLocalMessageIds ] before accepting the email
104
109
/// for delivery.
105
110
final String ? localMessageId;
111
+
112
+ /// The local part of a previous email sent by pub.dev, and to which the current
113
+ /// email is a reply-to. This will become the local part of the `In-Reply-To` and
114
+ /// the `References` SMTP headers.
115
+ final String ? inReplyToLocalMessageId;
116
+
106
117
final EmailAddress from;
107
118
final List <EmailAddress > recipients;
108
119
final List <EmailAddress > ccRecipients;
@@ -114,19 +125,27 @@ class EmailMessage {
114
125
this .recipients,
115
126
this .subject,
116
127
String bodyText, {
128
+ this .inReplyToLocalMessageId,
117
129
this .localMessageId,
118
130
this .ccRecipients = const < EmailAddress > [],
119
131
}) : bodyText = reflowBodyText (bodyText);
120
132
121
- /// Throws [ArgumentError] if the [localMessageId] field doesn't look like
122
- /// UUID or ULID .
133
+ /// Throws [ArgumentError] if the [localMessageId] or the
134
+ /// [inReplyToLocalMessageId] field doesn't look like an approved ID .
123
135
///
124
136
/// TODO: double-check that we follow https://www.jwz.org/doc/mid.html
125
- void verifyLocalMessageId () {
126
- final uuid = localMessageId;
127
- if (uuid == null || uuid.length < 25 || uuid.length > 36 ) {
128
- throw ArgumentError ('Invalid uuid: `$uuid `' );
137
+ void verifyLocalMessageIds () {
138
+ void verifyId (String ? id) {
139
+ if (id != null && ! _messageIdLocalPartRegExp.hasMatch (id)) {
140
+ throw ArgumentError ('Invalid message-id local part: `$id `' );
141
+ }
142
+ }
143
+
144
+ if (localMessageId == null ) {
145
+ throw ArgumentError ('`localMessageId` must be initialized.' );
129
146
}
147
+ verifyId (localMessageId);
148
+ verifyId (inReplyToLocalMessageId);
130
149
}
131
150
132
151
Map <String , Object ?> toJson () {
0 commit comments