Commit
+570 -2 +/-8 browse
1 | diff --git a/Cargo.lock b/Cargo.lock |
2 | index f80ce72..1e7864d 100644 |
3 | --- a/Cargo.lock |
4 | +++ b/Cargo.lock |
5 | @@ -796,6 +796,7 @@ dependencies = [ |
6 | "bytes", |
7 | "futures", |
8 | "mail-parser", |
9 | + "md5", |
10 | "melib", |
11 | "smtp-proto", |
12 | "thiserror", |
13 | @@ -818,6 +819,12 @@ dependencies = [ |
14 | ] |
15 | |
16 | [[package]] |
17 | + name = "md5" |
18 | + version = "0.7.0" |
19 | + source = "registry+https://github.com/rust-lang/crates.io-index" |
20 | + checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" |
21 | + |
22 | + [[package]] |
23 | name = "melib" |
24 | version = "0.8.6" |
25 | source = "registry+https://github.com/rust-lang/crates.io-index" |
26 | diff --git a/maitred/Cargo.toml b/maitred/Cargo.toml |
27 | index 81236de..9626221 100644 |
28 | --- a/maitred/Cargo.toml |
29 | +++ b/maitred/Cargo.toml |
30 | @@ -7,6 +7,7 @@ edition = "2021" |
31 | bytes = "1.6.1" |
32 | futures = "0.3.30" |
33 | mail-parser = { version = "0.9.3", features = ["serde", "serde_support"] } |
34 | + md5 = "0.7.0" |
35 | melib = { version = "0.8.6", default-features = false, features = ["base64", "smtp"] } |
36 | smtp-proto = { version = "0.1.5", features = ["serde", "serde_support"] } |
37 | thiserror = "1.0.63" |
38 | diff --git a/maitred/src/addresses.rs b/maitred/src/addresses.rs |
39 | new file mode 100644 |
40 | index 0000000..4728649 |
41 | --- /dev/null |
42 | +++ b/maitred/src/addresses.rs |
43 | @@ -0,0 +1,16 @@ |
44 | + use std::fmt::Display; |
45 | + |
46 | + use melib::Address; |
47 | + |
48 | + /// Array of resolved e-mail addresses that are associated with a mailing list |
49 | + #[derive(Debug)] |
50 | + pub struct Addresses(pub Vec<Address>); |
51 | + |
52 | + impl Display for Addresses { |
53 | + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
54 | + let addresses: Vec<String> = self.0.iter().map(|address| address.to_string()).collect(); |
55 | + write!(f, "{}", addresses.join("\n")) |
56 | + } |
57 | + } |
58 | + |
59 | + |
60 | diff --git a/maitred/src/expansion.rs b/maitred/src/expansion.rs |
61 | new file mode 100644 |
62 | index 0000000..72e1ddc |
63 | --- /dev/null |
64 | +++ b/maitred/src/expansion.rs |
65 | @@ -0,0 +1,40 @@ |
66 | + use std::{fmt::Display, result::Result as StdResult}; |
67 | + |
68 | + use crate::addresses::Addresses; |
69 | + |
70 | + pub type Result = StdResult<Addresses, Error>; |
71 | + |
72 | + /// An error encountered while expanding a mail address |
73 | + #[derive(Debug, thiserror::Error)] |
74 | + pub enum Error { |
75 | + /// Indicates an unspecified error that occurred during expansion |
76 | + #[error("Internal Server Error: {0}")] |
77 | + Server(String), |
78 | + /// Indicates that no group exists with the specified name |
79 | + #[error("Group Not Found: {0}")] |
80 | + NotFound(String), |
81 | + } |
82 | + |
83 | + /// Expands a string representing a mailing list to an array of the associated |
84 | + /// addresses within the list if it exists. NOTE: That this function should |
85 | + /// only be called with proper authentication otherwise it could be used to |
86 | + /// harvest e-mail addresses. |
87 | + pub trait Expansion { |
88 | + /// Expand the group into an array of members |
89 | + fn expand(&self, name: &str) -> Result; |
90 | + } |
91 | + |
92 | + /// Wrapper type implementing the Expansion trait |
93 | + pub struct Func<F>(pub F) |
94 | + where |
95 | + F: Fn(&str) -> Result; |
96 | + |
97 | + impl<F> Expansion for Func<F> |
98 | + where |
99 | + F: Fn(&str) -> Result, |
100 | + { |
101 | + fn expand(&self, name: &str) -> Result { |
102 | + let f = &self.0; |
103 | + f(name) |
104 | + } |
105 | + } |
106 | diff --git a/maitred/src/lib.rs b/maitred/src/lib.rs |
107 | index a010ec5..e523b2c 100644 |
108 | --- a/maitred/src/lib.rs |
109 | +++ b/maitred/src/lib.rs |
110 | @@ -1,8 +1,11 @@ |
111 | + mod addresses; |
112 | mod error; |
113 | + mod expansion; |
114 | mod pipeline; |
115 | mod server; |
116 | mod session; |
117 | mod transport; |
118 | + mod verify; |
119 | |
120 | use smtp_proto::{Request, Response as SmtpResponse}; |
121 | |
122 | diff --git a/maitred/src/session.rs b/maitred/src/session.rs |
123 | index d23d57d..4ef0078 100644 |
124 | --- a/maitred/src/session.rs |
125 | +++ b/maitred/src/session.rs |
126 | @@ -6,7 +6,9 @@ use melib::Address; |
127 | use smtp_proto::{EhloResponse, Request, Response as SmtpResponse}; |
128 | use url::Host; |
129 | |
130 | + use crate::expansion::Expansion; |
131 | use crate::transport::Response; |
132 | + use crate::verify::Verify; |
133 | use crate::{smtp_err, smtp_ok, smtp_response}; |
134 | |
135 | /// Result generated as part of an SMTP session, an Err indicates a session |
136 | @@ -53,6 +55,8 @@ pub(crate) struct Session { |
137 | maximum_size: u64, |
138 | capabilities: u32, |
139 | help_banner: String, |
140 | + list_expansion: Option<Box<dyn Expansion>>, |
141 | + verification: Option<Box<dyn Verify>>, |
142 | } |
143 | |
144 | impl Session { |
145 | @@ -76,6 +80,19 @@ impl Session { |
146 | self |
147 | } |
148 | |
149 | + pub fn list_expansion<T>(mut self, expansion: T) -> Self |
150 | + where |
151 | + T: crate::expansion::Expansion + 'static, |
152 | + { |
153 | + self.list_expansion = Some(Box::new(expansion)); |
154 | + self |
155 | + } |
156 | + |
157 | + pub fn verification(mut self, verification: Box<dyn Verify>) -> Self { |
158 | + self.verification = Some(verification); |
159 | + self |
160 | + } |
161 | + |
162 | pub fn reset(&mut self) { |
163 | self.body = None; |
164 | self.mail_from = None; |
165 | @@ -236,8 +253,56 @@ impl Session { |
166 | self.check_initialized()?; |
167 | smtp_ok!(250, 0, 0, 0, "OK".to_string()) |
168 | } |
169 | - Request::Vrfy { value } => todo!(), |
170 | - Request::Expn { value } => todo!(), |
171 | + Request::Vrfy { value } => { |
172 | + if let Some(verifier) = &self.verification { |
173 | + let address = Address::try_from(value.as_str()).map_err(|e| { |
174 | + smtp_response!(500, 0, 0, 0, format!("Cannot parse: {} {}", value, e)) |
175 | + })?; |
176 | + match verifier.verify(&address) { |
177 | + Ok(_) => { |
178 | + smtp_ok!(200, 0, 0, 0, "Ok".to_string()) |
179 | + } |
180 | + Err(e) => match e { |
181 | + crate::verify::Error::Server(e) => { |
182 | + smtp_err!(500, 0, 0, 0, e.to_string()) |
183 | + } |
184 | + crate::verify::Error::NotFound(e) => { |
185 | + smtp_err!(500, 0, 0, 0, e.to_string()) |
186 | + } |
187 | + crate::verify::Error::Ambiguous(alternatives) => { |
188 | + smtp_err!(500, 0, 0, 0, alternatives.to_string()) |
189 | + } |
190 | + }, |
191 | + } |
192 | + } else { |
193 | + smtp_err!(500, 0, 0, 0, "No such address") |
194 | + } |
195 | + } |
196 | + Request::Expn { value } => { |
197 | + if let Some(expn) = &self.list_expansion { |
198 | + match expn.expand(value) { |
199 | + Ok(addresses) => { |
200 | + smtp_ok!(250, 0, 0, 0, addresses.to_string()) |
201 | + } |
202 | + Err(err) => match err { |
203 | + crate::expansion::Error::Server(message) => { |
204 | + smtp_err!( |
205 | + 500, |
206 | + 0, |
207 | + 0, |
208 | + 0, |
209 | + format!("Internal mailing list error: {}", message) |
210 | + ) |
211 | + } |
212 | + crate::expansion::Error::NotFound(name) => { |
213 | + smtp_err!(500, 0, 0, 0, format!("No such mailing list: {}", name)) |
214 | + } |
215 | + }, |
216 | + } |
217 | + } else { |
218 | + smtp_err!(500, 0, 0, 0, "Server does not support EXPN") |
219 | + } |
220 | + } |
221 | Request::Help { value } => { |
222 | self.check_initialized()?; |
223 | if value.is_empty() { |
224 | diff --git a/maitred/src/verify.rs b/maitred/src/verify.rs |
225 | new file mode 100644 |
226 | index 0000000..a1bf270 |
227 | --- /dev/null |
228 | +++ b/maitred/src/verify.rs |
229 | @@ -0,0 +1,41 @@ |
230 | + use std::{fmt::Display, result::Result as StdResult}; |
231 | + |
232 | + use crate::addresses::Addresses; |
233 | + use melib::Address; |
234 | + |
235 | + pub type Result = StdResult<(), Error>; |
236 | + |
237 | + /// An error encountered while verifying an e-mail address |
238 | + #[derive(Debug, thiserror::Error)] |
239 | + pub enum Error { |
240 | + /// Indicates an unspecified error that occurred during expansion |
241 | + #[error("Internal Server Error: {0}")] |
242 | + Server(String), |
243 | + /// Indicates that no group exists with the specified name |
244 | + #[error("Group Not Found: {0}")] |
245 | + NotFound(String), |
246 | + /// Indicates that the input as ambigious and multiple addresses are |
247 | + /// associated with the string. |
248 | + #[error("Name is Ambiguous: {0}")] |
249 | + Ambiguous(Addresses), |
250 | + } |
251 | + |
252 | + pub trait Verify { |
253 | + /// Verify the e-mail address on the server |
254 | + fn verify(&self, address: &Address) -> Result; |
255 | + } |
256 | + |
257 | + /// Wrapper type implementing the Verify trait |
258 | + pub struct Func<F>(pub F) |
259 | + where |
260 | + F: Fn(&Address) -> Result; |
261 | + |
262 | + impl<F> Verify for Func<F> |
263 | + where |
264 | + F: Fn(&Address) -> Result, |
265 | + { |
266 | + fn verify(&self, address: &Address) -> Result { |
267 | + let f = &self.0; |
268 | + f(address) |
269 | + } |
270 | + } |
271 | diff --git a/rfcs/rfc2033.txt b/rfcs/rfc2033.txt |
272 | new file mode 100644 |
273 | index 0000000..a47433e |
274 | --- /dev/null |
275 | +++ b/rfcs/rfc2033.txt |
276 | @@ -0,0 +1,395 @@ |
277 | + |
278 | + |
279 | + |
280 | + |
281 | + |
282 | + |
283 | + Network Working Group J. Myers |
284 | + Request for Comments: 2033 Carnegie Mellon |
285 | + Category: Informational October 1996 |
286 | + |
287 | + |
288 | + Local Mail Transfer Protocol |
289 | + |
290 | + Status of this Memo |
291 | + |
292 | + This memo provides information for the Internet community. This memo |
293 | + does not specify an Internet standard of any kind. Distribution of |
294 | + this memo is unlimited. |
295 | + |
296 | + 1. Abstract |
297 | + |
298 | + SMTP [SMTP] [HOST-REQ] and its service extensions [ESMTP] provide a |
299 | + mechanism for transferring mail reliably and efficiently. The design |
300 | + of the SMTP protocol effectively requires the server to manage a mail |
301 | + delivery queue. |
302 | + |
303 | + In some limited circumstances, outside the area of mail exchange |
304 | + between independent hosts on public networks, it is desirable to |
305 | + implement a system where a mail receiver does not manage a queue. |
306 | + This document describes the LMTP protocol for transporting mail into |
307 | + such systems. |
308 | + |
309 | + Although LMTP is an alternative protocol to ESMTP, it uses (with a |
310 | + few changes) the syntax and semantics of ESMTP. This design permits |
311 | + LMTP to utilize the extensions defined for ESMTP. LMTP should be |
312 | + used only by specific prior arrangement and configuration, and it |
313 | + MUST NOT be used on TCP port 25. |
314 | + |
315 | + Table of Contents |
316 | + |
317 | + 1. Abstract ................................................ 1 |
318 | + 2. Conventions Used in this Document ....................... 2 |
319 | + 3. Introduction and Overview ............................... 2 |
320 | + 4. The LMTP protocol ....................................... 3 |
321 | + 4.1. The LHLO, HELO and EHLO commands ........................ 4 |
322 | + 4.2. The DATA command ........................................ 4 |
323 | + 4.3. The BDAT command ........................................ 5 |
324 | + 5. Implementation requirements ............................. 6 |
325 | + 6. Acknowledgments ......................................... 6 |
326 | + 7. References .............................................. 7 |
327 | + 8. Security Considerations ................................. 7 |
328 | + 9. Author's Address ........................................ 7 |
329 | + |
330 | + |
331 | + |
332 | + |
333 | + |
334 | + Myers Informational [Page 1] |
335 | + |
336 | + RFC 2033 LMTP October 1996 |
337 | + |
338 | + |
339 | + 2. Conventions Used in this Document |
340 | + |
341 | + In examples, "C:" and "S:" indicate lines sent by the client and |
342 | + server respectively. |
343 | + |
344 | + 3. Introduction and Overview |
345 | + |
346 | + The design of the SMTP protocol effectively requires the server to |
347 | + manage a mail delivery queue. This is because a single mail |
348 | + transaction may specify multiple recipients and the final "." of the |
349 | + DATA command may return only one reply code, to indicate the status |
350 | + of the entire transaction. If, for example, a server is given a |
351 | + transaction for two recipients, delivery to the first succeeds, and |
352 | + delivery to the second encounters a temporary failure condition, |
353 | + there is no mechanism to inform the client of the situation. The |
354 | + server must queue the message and later attempt to deliver it to the |
355 | + second recipient. |
356 | + |
357 | + This queuing requirement is beneficial in the situation for which |
358 | + SMTP was originally designed: store-and-forward relay of mail between |
359 | + networked hosts. In some limited situations, it is desirable to have |
360 | + a server which does not manage a queue, instead relying on the client |
361 | + to perform queue management. As an example, consider a hypothetical |
362 | + host with a mail system designed as follows: |
363 | + |
364 | + |
365 | + |
366 | + TCP port 25 +-----------------+ |
367 | + ---------------------->| | ######### |
368 | + | Queue |<># Mail # |
369 | + TCP port 25 | Manager | # Queue # |
370 | + <----------------------| | ######### |
371 | + +-----------------+ |
372 | + Local * ^ Local * Local |
373 | + IPC * | IPC * IPC |
374 | + * | * |
375 | + * | * |
376 | + * | * |
377 | + V | V |
378 | + Non-SMTP +----------+ +----------+ |
379 | + Protocol | Gateway | | Local | ######### |
380 | + <==============>| Delivery | | Delivery |>># Mail # |
381 | + | Agent | | Agent | # Spool # |
382 | + +----------+ +----------+ ######### |
383 | + |
384 | + |
385 | + The host's mail system has three independent, communicating |
386 | + subsystems. The first is a queue manager, which acts as a |
387 | + |
388 | + |
389 | + |
390 | + Myers Informational [Page 2] |
391 | + |
392 | + RFC 2033 LMTP October 1996 |
393 | + |
394 | + |
395 | + traditional SMTP agent, transferring messages to and from other hosts |
396 | + over TCP and managing a mail queue in persistent storage. The other |
397 | + two are agents which handle delivery for addresses in domains for |
398 | + which the host takes responsibility. One agent performs gatewaying |
399 | + to and from some other mail system. The other agent delivers the |
400 | + message into a persistent mail spool. |
401 | + |
402 | + It would be desirable to use SMTP over a local inter-process |
403 | + communication channel to transfer messages from the queue manager to |
404 | + the delivery agents. It would, however, significantly increase the |
405 | + complexity of the delivery agents to require them to manage their own |
406 | + mail queues. |
407 | + |
408 | + The common practice of invoking a delivery agent with the envelope |
409 | + address(es) as command-line arguments, then having the delivery agent |
410 | + communicate status with an exit code has three serious problems: the |
411 | + agent can only return one exit code to be applied to all recipients, |
412 | + it is difficult to extend the interface to deal with ESMTP extensions |
413 | + such as DSN [DSN] and ENHANCEDSTATUSCODES [ENHANCEDSTATUSCODES], and |
414 | + exits performed by system libraries due to temporary conditions |
415 | + frequently get interpreted as permanent errors. |
416 | + |
417 | + The LMTP protocol causes the server to return, after the final "." of |
418 | + the DATA command, one reply for each recipient. Therefore, if the |
419 | + queue manager is configured to use LMTP instead of SMTP when |
420 | + transferring messages to the delivery agents, then the delivery |
421 | + agents may attempt delivery to each recipient after the final "." and |
422 | + individually report the status for each recipient. Connections which |
423 | + should use the LMTP protocol are drawn in the diagram above using |
424 | + asterisks. |
425 | + |
426 | + Note that it is not beneficial to use the LMTP protocol when |
427 | + transferring messages to the queue manager, either from the network |
428 | + or from a delivery agent. The queue manager does implement a mail |
429 | + queue, so it may store the message and take responsibility for later |
430 | + delivering it. |
431 | + |
432 | + 4. The LMTP protocol |
433 | + |
434 | + The LMTP protocol is identical to the SMTP protocol SMTP [SMTP] |
435 | + [HOST-REQ] with its service extensions [ESMTP], except as modified by |
436 | + this document. |
437 | + |
438 | + A "successful" RCPT command is defined as an RCPT command which |
439 | + returns a Positive Completion reply code. |
440 | + |
441 | + A "Positive Completion reply code" is defined in Appendix E of STD |
442 | + 10, RFC 821 [SMTP] as a reply code which "2" as the first digit. |
443 | + |
444 | + |
445 | + |
446 | + Myers Informational [Page 3] |
447 | + |
448 | + RFC 2033 LMTP October 1996 |
449 | + |
450 | + |
451 | + 4.1. The LHLO, HELO and EHLO commands |
452 | + |
453 | + The HELO and EHLO commands of ESMTP are replaced by the LHLO command. |
454 | + This permits a misconfiguration where both parties are not using the |
455 | + same protocol to be detected. |
456 | + |
457 | + The LHLO command has identical semantics to the EHLO command of ESMTP |
458 | + [ESMTP]. |
459 | + |
460 | + The HELO and EHLO commands of ESMTP are not present in LMTP. A LMTP |
461 | + server MUST NOT return a Postive Completion reply code to these |
462 | + commands. The 500 reply code is recommended. |
463 | + |
464 | + 4.2. The DATA command |
465 | + |
466 | + In the LMTP protocol, there is one additional restriction placed on |
467 | + the DATA command, and one change to how replies to the final "." are |
468 | + sent. |
469 | + |
470 | + The additional restriction is that when there have been no successful |
471 | + RCPT commands in the mail transaction, the DATA command MUST fail |
472 | + with a 503 reply code. |
473 | + |
474 | + The change is that after the final ".", the server returns one reply |
475 | + for each previously successful RCPT command in the mail transaction, |
476 | + in the order that the RCPT commands were issued. Even if there were |
477 | + multiple successful RCPT commands giving the same forward-path, there |
478 | + must be one reply for each successful RCPT command. |
479 | + |
480 | + When one of these replies to the final "." is a Positive Completion |
481 | + reply, the server is accepting responsibility for delivering or |
482 | + relying the message to the corresponding recipient. It must take |
483 | + this responsibility seriously, i.e., it MUST NOT lose the message for |
484 | + frivolous reasons, e.g., because the host later crashes or because of |
485 | + a predictable resource shortage. |
486 | + |
487 | + A multiline reply is still considered a single reply and corresponds |
488 | + to a single RCPT command. |
489 | + |
490 | + EXAMPLE: |
491 | + |
492 | + S: 220 foo.edu LMTP server ready |
493 | + C: LHLO foo.edu |
494 | + S: 250-foo.edu |
495 | + S: 250-PIPELINING |
496 | + S: 250 SIZE |
497 | + C: MAIL FROM:<chris@bar.com> |
498 | + S: 250 OK |
499 | + |
500 | + |
501 | + |
502 | + Myers Informational [Page 4] |
503 | + |
504 | + RFC 2033 LMTP October 1996 |
505 | + |
506 | + |
507 | + C: RCPT TO:<pat@foo.edu> |
508 | + S: 250 OK |
509 | + C: RCPT TO:<jones@foo.edu> |
510 | + S: 550 No such user here |
511 | + C: RCPT TO:<green@foo.edu> |
512 | + S: 250 OK |
513 | + C: DATA |
514 | + S: 354 Start mail input; end with <CRLF>.<CRLF> |
515 | + C: Blah blah blah... |
516 | + C: ...etc. etc. etc. |
517 | + C: . |
518 | + S: 250 OK |
519 | + S: 452 <green@foo.edu> is temporarily over quota |
520 | + C: QUIT |
521 | + S: 221 foo.edu closing connection |
522 | + |
523 | + |
524 | + NOTE: in the above example, the domain names of both the client and |
525 | + server are identical. This is because in the example the client and |
526 | + server are different subsystems of the same mail domain. |
527 | + |
528 | + 4.3. The BDAT command |
529 | + |
530 | + If the server supports the ESMTP CHUNKING extension [BINARYMIME], a |
531 | + BDAT command containing the LAST parameter returns one reply for each |
532 | + previously successful RCPT command in the mail transaction, in the |
533 | + order that the RCPT commands were issued. Even if there were |
534 | + multiple successful RCPT commands giving the same forward-path, there |
535 | + must be one reply for each successful RCPT command. If there were no |
536 | + previously successful RCPT commands in the mail transaction, then the |
537 | + BDAT LAST command returns zero replies. |
538 | + |
539 | + When one of these replies to the BDAT LAST command is a Positive |
540 | + Completion reply, the server is accepting responsibility for |
541 | + delivering or relaying the message to the corresponding recipient. |
542 | + It must take this responsibility seriously, i.e., it MUST NOT lose |
543 | + the message for frivolous reasons, e.g., because the host later |
544 | + crashes or because of a predictable resource shortage. |
545 | + |
546 | + A multiline reply is still considered a single reply and corresponds |
547 | + to a single RCPT command. |
548 | + |
549 | + The behavior of BDAT commands without the LAST parameter is not |
550 | + changed; they still return exactly one reply. |
551 | + |
552 | + |
553 | + |
554 | + |
555 | + |
556 | + |
557 | + |
558 | + Myers Informational [Page 5] |
559 | + |
560 | + RFC 2033 LMTP October 1996 |
561 | + |
562 | + |
563 | + 5. Implementation requirements |
564 | + |
565 | + As LMTP is a different protocol than SMTP, it MUST NOT be used on the |
566 | + TCP service port 25. |
567 | + |
568 | + A server implementation MUST implement the PIPELINING [PIPELINING] |
569 | + and ENHANCEDSTATUSCODES [ENHANCEDSTATUSCODES] ESMTP extensions. A |
570 | + server implementation SHOULD implement the 8BITMIME [8BITMIME] |
571 | + extension. |
572 | + |
573 | + Use of LMTP can aggravate the situation described in [DUP-MSGS]. To |
574 | + avoid this synchronization problem, the following requirements are |
575 | + made of implementations: |
576 | + |
577 | + A server implementation which is capable of quickly accepting |
578 | + responsibility for delivering or relaying a message to multiple |
579 | + recipients and which is capable of sending any necessary notification |
580 | + messages SHOULD NOT implement the LMTP protocol. |
581 | + |
582 | + The LMTP protocol SHOULD NOT be used over wide area networks. |
583 | + |
584 | + The server SHOULD send each reply as soon as possible. If it is |
585 | + going to spend a nontrivial amount of time handling delivery for the |
586 | + next recipient, it SHOULD flush any outgoing LMTP buffer, so the |
587 | + reply may be quickly received by the client. |
588 | + |
589 | + The client SHOULD process the replies as they come in, instead of |
590 | + waiting for all of the replies to arrive before processing any of |
591 | + them. If the connection closes after replies for some, but not all, |
592 | + recipients have arrived, the client MUST process the replies that |
593 | + arrived and treat the rest as temporary failures. |
594 | + |
595 | + 6. Acknowledgments |
596 | + |
597 | + This work is a refinement of the MULT extension, which was invented |
598 | + by Jeff Michaud and was used in implementing gateways to the Mail-11 |
599 | + mail system. |
600 | + |
601 | + Many thanks to Matt Thomas for assisting me in understanding the |
602 | + semantics of the Mail-11 MULT extension. |
603 | + |
604 | + |
605 | + |
606 | + |
607 | + |
608 | + |
609 | + |
610 | + |
611 | + |
612 | + |
613 | + |
614 | + Myers Informational [Page 6] |
615 | + |
616 | + RFC 2033 LMTP October 1996 |
617 | + |
618 | + |
619 | + 7. References |
620 | + |
621 | + [8BITMIME] Klensin, J., et. al, "SMTP Service Extension for 8bit-MIME |
622 | + transport", RFC 1652, July 1994. |
623 | + |
624 | + [BINARYMIME] Vaudreuil, G., "SMTP Service Extensions for Transmission |
625 | + of Large and Binary MIME Messages", RFC 1830, August 1995. |
626 | + |
627 | + [DSN] Moore, K., Vaudreuil, G., "An Extensible Message Format for |
628 | + Delivery Status Notifications", RFC 1894, January 1996. |
629 | + |
630 | + [DUP-MSGS] Partridge, C., "Duplicate messages and SMTP", RFC 1047, |
631 | + February 1988. |
632 | + |
633 | + [ENHANCEDSTATUSCODES] Freed, N., "SMTP Service Extension for |
634 | + Returning Enhanced Error Codes", RFC 2034, October 1996. |
635 | + |
636 | + [ESMTP] Rose, M., Stefferud, E., Crocker, C., Klensin, J., Freed, N., |
637 | + "SMTP Service Extensions", RFC 1869, November 1995. |
638 | + |
639 | + [HOST-REQ] Braden, R., "Requirements for Internet hosts - application |
640 | + and support", STD 3, RFC 1123 section 5, October 1989. |
641 | + |
642 | + [PIPELINING] Freed, N., Cargille, A, "SMTP Service Extension for |
643 | + Command Pipelining", RFC 1854, October 1995. |
644 | + |
645 | + [SMTP] Postel, J., "Simple Mail Transfer Protocol", STD 10, RFC 821, |
646 | + August 1982. |
647 | + |
648 | + |
649 | + There are no known security issues with the issues in this memo. |
650 | + |
651 | + 9. Author's Address |
652 | + |
653 | + John G. Myers |
654 | + Carnegie-Mellon University |
655 | + 5000 Forbes Ave. |
656 | + Pittsburgh PA, 15213-3890 |
657 | + |
658 | + EMail: jgm+@cmu.edu |
659 | + |
660 | + |
661 | + |
662 | + |
663 | + |
664 | + |
665 | + |
666 | + |
667 | + |
668 | + |
669 | + |
670 | + Myers Informational [Page 7] |
671 | + |