Skip to main content

smtp_proto/response/
generate.rs

1/*
2 * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
3 *
4 * SPDX-License-Identifier: Apache-2.0 OR MIT
5 */
6
7use std::{
8    fmt::Display,
9    io::{self, Write},
10};
11
12use crate::*;
13
14impl<T: Display> EhloResponse<T> {
15    pub fn new(hostname: T) -> Self {
16        Self {
17            hostname,
18            capabilities: 0,
19            auth_mechanisms: 0,
20            deliver_by: 0,
21            future_release_interval: 0,
22            future_release_datetime: 0,
23            mt_priority: MtPriority::Mixer,
24            no_soliciting: None,
25            size: 0,
26        }
27    }
28
29    pub fn write(&self, mut writer: impl Write) -> io::Result<()> {
30        write!(writer, "250-{} you had me at EHLO\r\n", self.hostname)?;
31        let mut capabilities = self.capabilities;
32
33        while capabilities != 0 {
34            let capability = 1 << (31 - capabilities.leading_zeros());
35            capabilities ^= capability;
36
37            writer.write_all(b"250")?;
38            writer.write_all(if capabilities != 0 { b"-" } else { b" " })?;
39            match capability {
40                EXT_8BIT_MIME => write!(writer, "8BITMIME\r\n"),
41                EXT_ATRN => write!(writer, "ATRN\r\n"),
42                EXT_AUTH => {
43                    writer.write_all(b"AUTH")?;
44                    let mut mechanisms = self.auth_mechanisms;
45                    while mechanisms != 0 {
46                        let item = 1 << (63 - mechanisms.leading_zeros());
47                        mechanisms ^= item;
48                        write!(writer, " {}", item.to_mechanism())?;
49                    }
50                    writer.write_all(b"\r\n")
51                }
52                EXT_BINARY_MIME => write!(writer, "BINARYMIME\r\n"),
53                EXT_BURL => write!(writer, "BURL\r\n"),
54                EXT_CHECKPOINT => write!(writer, "CHECKPOINT\r\n"),
55                EXT_CHUNKING => write!(writer, "CHUNKING\r\n"),
56                EXT_CONNEG => write!(writer, "CONNEG\r\n"),
57                EXT_CONPERM => write!(writer, "CONPERM\r\n"),
58                EXT_DELIVER_BY => {
59                    if self.deliver_by > 0 {
60                        write!(writer, "DELIVERBY {}\r\n", self.deliver_by)
61                    } else {
62                        write!(writer, "DELIVERBY\r\n")
63                    }
64                }
65                EXT_DSN => write!(writer, "DSN\r\n"),
66                EXT_ENHANCED_STATUS_CODES => write!(writer, "ENHANCEDSTATUSCODES\r\n"),
67                EXT_ETRN => write!(writer, "ETRN\r\n"),
68                EXT_EXPN => write!(writer, "EXPN\r\n"),
69                EXT_VRFY => write!(writer, "VRFY\r\n"),
70                EXT_FUTURE_RELEASE => write!(
71                    writer,
72                    "FUTURERELEASE {} {}\r\n",
73                    self.future_release_interval, self.future_release_datetime
74                ),
75                EXT_HELP => write!(writer, "HELP\r\n"),
76                EXT_MT_PRIORITY => write!(
77                    writer,
78                    "MT-PRIORITY {}\r\n",
79                    match self.mt_priority {
80                        MtPriority::Mixer => "MIXER",
81                        MtPriority::Stanag4406 => "STANAG4406",
82                        MtPriority::Nsep => "NSEP",
83                    }
84                ),
85                EXT_MTRK => write!(writer, "MTRK\r\n"),
86                EXT_NO_SOLICITING => {
87                    if let Some(keywords) = &self.no_soliciting {
88                        write!(writer, "NO-SOLICITING {keywords}\r\n")
89                    } else {
90                        write!(writer, "NO-SOLICITING\r\n")
91                    }
92                }
93                EXT_ONEX => write!(writer, "ONEX\r\n"),
94                EXT_PIPELINING => write!(writer, "PIPELINING\r\n"),
95                EXT_REQUIRE_TLS => write!(writer, "REQUIRETLS\r\n"),
96                EXT_RRVS => write!(writer, "RRVS\r\n"),
97                EXT_SIZE => {
98                    if self.size > 0 {
99                        write!(writer, "SIZE {}\r\n", self.size)
100                    } else {
101                        write!(writer, "SIZE\r\n")
102                    }
103                }
104                EXT_SMTP_UTF8 => write!(writer, "SMTPUTF8\r\n"),
105                EXT_START_TLS => write!(writer, "STARTTLS\r\n"),
106                EXT_VERB => write!(writer, "VERB\r\n"),
107                _ => write!(writer, ""),
108            }?;
109        }
110
111        Ok(())
112    }
113}
114
115impl<T: Display> Response<T> {
116    pub fn write(&self, mut writer: impl Write) -> io::Result<()> {
117        write!(
118            writer,
119            "{} {}.{}.{} {}\r\n",
120            self.code, self.esc[0], self.esc[1], self.esc[2], self.message
121        )
122    }
123}
124
125pub trait BitToString {
126    fn to_mechanism(&self) -> &'static str;
127}
128
129impl BitToString for u64 {
130    fn to_mechanism(&self) -> &'static str {
131        match *self {
132            AUTH_SCRAM_SHA_256_PLUS => "SCRAM-SHA-256-PLUS",
133            AUTH_SCRAM_SHA_256 => "SCRAM-SHA-256",
134            AUTH_SCRAM_SHA_1_PLUS => "SCRAM-SHA-1-PLUS",
135            AUTH_SCRAM_SHA_1 => "SCRAM-SHA-1",
136            AUTH_OAUTHBEARER => "OAUTHBEARER",
137            AUTH_XOAUTH => "XOAUTH",
138            AUTH_XOAUTH2 => "XOAUTH2",
139            AUTH_9798_M_DSA_SHA1 => "9798-M-DSA-SHA1",
140            AUTH_9798_M_ECDSA_SHA1 => "9798-M-ECDSA-SHA1",
141            AUTH_9798_M_RSA_SHA1_ENC => "9798-M-RSA-SHA1-ENC",
142            AUTH_9798_U_DSA_SHA1 => "9798-U-DSA-SHA1",
143            AUTH_9798_U_ECDSA_SHA1 => "9798-U-ECDSA-SHA1",
144            AUTH_9798_U_RSA_SHA1_ENC => "9798-U-RSA-SHA1-ENC",
145            AUTH_EAP_AES128 => "EAP-AES128",
146            AUTH_EAP_AES128_PLUS => "EAP-AES128-PLUS",
147            AUTH_ECDH_X25519_CHALLENGE => "ECDH-X25519-CHALLENGE",
148            AUTH_ECDSA_NIST256P_CHALLENGE => "ECDSA-NIST256P-CHALLENGE",
149            AUTH_EXTERNAL => "EXTERNAL",
150            AUTH_GS2_KRB5 => "GS2-KRB5",
151            AUTH_GS2_KRB5_PLUS => "GS2-KRB5-PLUS",
152            AUTH_GSS_SPNEGO => "GSS-SPNEGO",
153            AUTH_GSSAPI => "GSSAPI",
154            AUTH_KERBEROS_V4 => "KERBEROS_V4",
155            AUTH_KERBEROS_V5 => "KERBEROS_V5",
156            AUTH_NMAS_SAMBA_AUTH => "NMAS-SAMBA-AUTH",
157            AUTH_NMAS_AUTHEN => "NMAS_AUTHEN",
158            AUTH_NMAS_LOGIN => "NMAS_LOGIN",
159            AUTH_NTLM => "NTLM",
160            AUTH_OAUTH10A => "OAUTH10A",
161            AUTH_OPENID20 => "OPENID20",
162            AUTH_OTP => "OTP",
163            AUTH_SAML20 => "SAML20",
164            AUTH_SECURID => "SECURID",
165            AUTH_SKEY => "SKEY",
166            AUTH_SPNEGO => "SPNEGO",
167            AUTH_SPNEGO_PLUS => "SPNEGO-PLUS",
168            AUTH_SXOVER_PLUS => "SXOVER-PLUS",
169            AUTH_CRAM_MD5 => "CRAM-MD5",
170            AUTH_DIGEST_MD5 => "DIGEST-MD5",
171            AUTH_LOGIN => "LOGIN",
172            AUTH_PLAIN => "PLAIN",
173            AUTH_ANONYMOUS => "ANONYMOUS",
174            _ => "",
175        }
176    }
177}
178
179impl<T: Display> Response<T> {
180    pub fn new(code: u16, e0: u8, e1: u8, e2: u8, message: T) -> Self {
181        Self {
182            code,
183            esc: [e0, e1, e2],
184            message,
185        }
186    }
187
188    /// Returns the reply's numeric status.
189    pub fn code(&self) -> u16 {
190        self.code
191    }
192
193    /// Returns the message included in the reply.
194    pub fn message(&self) -> &T {
195        &self.message
196    }
197
198    /// Returns the status severity (first digit of the status code).
199    pub fn severity(&self) -> Severity {
200        match self.code {
201            200..=299 => Severity::PositiveCompletion,
202            300..=399 => Severity::PositiveIntermediate,
203            400..=499 => Severity::TransientNegativeCompletion,
204            500..=599 => Severity::PermanentNegativeCompletion,
205            _ => Severity::Invalid,
206        }
207    }
208
209    /// Returns the status category (second digit of the status code).
210    pub fn category(&self) -> Category {
211        match (self.code / 10) % 10 {
212            0 => Category::Syntax,
213            1 => Category::Information,
214            2 => Category::Connections,
215            3 => Category::Unspecified3,
216            4 => Category::Unspecified4,
217            5 => Category::MailSystem,
218            _ => Category::Invalid,
219        }
220    }
221
222    /// Returns the status details (third digit of the status code).
223    pub fn details(&self) -> u16 {
224        self.code % 10
225    }
226
227    /// Returns `true` if the reply is a positive completion.
228    pub fn is_positive_completion(&self) -> bool {
229        self.severity() == Severity::PositiveCompletion
230    }
231
232    pub fn explain_class_code(&self) -> Option<(&'static str, &'static str)> {
233        match self.esc[0] {
234            2 => (
235                "Success",
236                concat!(
237                    "Success specifies that the DSN is reporting a posi",
238                    "tive delivery action. Detail sub-codes may provide",
239                    " notification of transformations required for deli",
240                    "very."
241                ),
242            )
243                .into(),
244            4 => (
245                "Persistent Transient Failure",
246                concat!(
247                    "A persistent transient failure is one in which the",
248                    " message as sent is valid, but persistence of some",
249                    " temporary condition has caused abandonment or del",
250                    "ay of attempts to send the message. If this code a",
251                    "ccompanies a delivery failure report, sending in t",
252                    "he future may be successful."
253                ),
254            )
255                .into(),
256            5 => (
257                "Permanent Failure",
258                concat!(
259                    "A permanent failure is one which is not likely to ",
260                    "be resolved by resending the message in the curren",
261                    "t form. Some change to the message or the destinat",
262                    "ion must be made for successful delivery."
263                ),
264            )
265                .into(),
266            _ => None,
267        }
268    }
269
270    pub fn explain_subject_code(&self) -> Option<(&'static str, &'static str)> {
271        match self.esc[1] {
272            0 => (
273                "Other or Undefined Status",
274                concat!("There is no additional subject information availab", "le."),
275            )
276                .into(),
277            1 => (
278                "Addressing Status",
279                concat!(
280                    "The address status reports on the originator or de",
281                    "stination address. It may include address syntax o",
282                    "r validity. These errors can generally be correcte",
283                    "d by the sender and retried."
284                ),
285            )
286                .into(),
287            2 => (
288                "Mailbox Status",
289                concat!(
290                    "Mailbox status indicates that something having to ",
291                    "do with the mailbox has caused this DSN. Mailbox i",
292                    "ssues are assumed to be under the general control ",
293                    "of the recipient."
294                ),
295            )
296                .into(),
297            3 => (
298                "Mail System Status",
299                concat!(
300                    "Mail system status indicates that something having",
301                    " to do with the destination system has caused this",
302                    " DSN. System issues are assumed to be under the ge",
303                    "neral control of the destination system administra",
304                    "tor."
305                ),
306            )
307                .into(),
308            4 => (
309                "Network and Routing Status",
310                concat!(
311                    "The networking or routing codes report status abou",
312                    "t the delivery system itself. These system compone",
313                    "nts include any necessary infrastructure such as d",
314                    "irectory and routing services. Network issues are ",
315                    "assumed to be under the control of the destination",
316                    " or intermediate system administrator."
317                ),
318            )
319                .into(),
320            5 => (
321                "Mail Delivery Protocol Status",
322                concat!(
323                    "The mail delivery protocol status codes report fai",
324                    "lures involving the message delivery protocol. The",
325                    "se failures include the full range of problems res",
326                    "ulting from implementation errors or an unreliable",
327                    " connection."
328                ),
329            )
330                .into(),
331            6 => (
332                "Message Content or Media Status",
333                concat!(
334                    "The message content or media status codes report f",
335                    "ailures involving the content of the message. Thes",
336                    "e codes report failures due to translation, transc",
337                    "oding, or otherwise unsupported message media. Mes",
338                    "sage content or media issues are under the control",
339                    " of both the sender and the receiver, both of whic",
340                    "h must support a common set of supported content-t",
341                    "ypes."
342                ),
343            )
344                .into(),
345            7 => (
346                "Security or Policy Status",
347                concat!(
348                    "The security or policy status codes report failure",
349                    "s involving policies such as per-recipient or per-",
350                    "host filtering and cryptographic operations. Secur",
351                    "ity and policy status issues are assumed to be und",
352                    "er the control of either or both the sender and re",
353                    "cipient. Both the sender and recipient must permit",
354                    " the exchange of messages and arrange the exchange",
355                    " of necessary keys and certificates for cryptograp",
356                    "hic operations."
357                ),
358            )
359                .into(),
360
361            _ => None,
362        }
363    }
364
365    pub fn explain_status_code(&self) -> Option<(&'static str, &'static str)> {
366        match (self.esc[1], self.esc[2]) {
367            (0, 0) => (
368                "Other undefined Status",
369                concat!(
370                    "Other undefined status is the only undefined error",
371                    " code."
372                ),
373            )
374                .into(),
375            (1, 0) => (
376                "Other address status",
377                concat!(
378                    "Something about the address specified in the messa",
379                    "ge caused this DSN."
380                ),
381            )
382                .into(),
383            (1, 1) => (
384                "Bad destination mailbox address",
385                concat!(
386                    "The mailbox specified in the address does not exis",
387                    "t. For Internet mail names, this means the address",
388                    " portion to the left of the \"@\" sign is invalid.",
389                    " This code is only useful for permanent failures."
390                ),
391            )
392                .into(),
393            (1, 2) => (
394                "Bad destination system address",
395                concat!(
396                    "The destination system specified in the address do",
397                    "es not exist or is incapable of accepting mail. Fo",
398                    "r Internet mail names, this means the address port",
399                    "ion to the right of the \"@\" is invalid for mail.",
400                    " This code is only useful for permanent failures."
401                ),
402            )
403                .into(),
404            (1, 3) => (
405                "Bad destination mailbox address syntax",
406                concat!(
407                    "The destination address was syntactically invalid.",
408                    " This can apply to any field in the address. This ",
409                    "code is only useful for permanent failures."
410                ),
411            )
412                .into(),
413            (1, 4) => (
414                "Destination mailbox address ambiguous",
415                concat!(
416                    "The mailbox address as specified matches one or mo",
417                    "re recipients on the destination system. This may ",
418                    "result if a heuristic address mapping algorithm is",
419                    " used to map the specified address to a local mail",
420                    "box name."
421                ),
422            )
423                .into(),
424            (1, 5) => (
425                "Destination address valid",
426                concat!(
427                    "This mailbox address as specified was valid. This ",
428                    "status code should be used for positive delivery r",
429                    "eports."
430                ),
431            )
432                .into(),
433            (1, 6) => (
434                "Destination mailbox has moved, No forwarding address",
435                concat!(
436                    "The mailbox address provided was at one time valid",
437                    ", but mail is no longer being accepted for that ad",
438                    "dress. This code is only useful for permanent fail",
439                    "ures."
440                ),
441            )
442                .into(),
443            (1, 7) => (
444                "Bad sender's mailbox address syntax",
445                concat!(
446                    "The sender's address was syntactically invalid. Th",
447                    "is can apply to any field in the address."
448                ),
449            )
450                .into(),
451            (1, 8) => (
452                "Bad sender's system address",
453                concat!(
454                    "The sender's system specified in the address does ",
455                    "not exist or is incapable of accepting return mail",
456                    ". For domain names, this means the address portion",
457                    " to the right of the \"@\" is invalid for mail."
458                ),
459            )
460                .into(),
461            (1, 9) => (
462                "Message relayed to non-compliant mailer",
463                concat!(
464                    "The mailbox address specified was valid, but the m",
465                    "essage has been relayed to a system that does not ",
466                    "speak this protocol; no further information can be",
467                    " provided."
468                ),
469            )
470                .into(),
471            (1, 10) => (
472                "Recipient address has null MX",
473                concat!(
474                    "This status code is returned when the associated a",
475                    "ddress is marked as invalid using a null MX."
476                ),
477            )
478                .into(),
479            (2, 0) => (
480                "Other or undefined mailbox status",
481                concat!(
482                    "The mailbox exists, but something about the destin",
483                    "ation mailbox has caused the sending of this DSN."
484                ),
485            )
486                .into(),
487            (2, 1) => (
488                "Mailbox disabled, not accepting messages",
489                concat!(
490                    "The mailbox exists, but is not accepting messages.",
491                    " This may be a permanent error if the mailbox will",
492                    " never be re-enabled or a transient error if the m",
493                    "ailbox is only temporarily disabled."
494                ),
495            )
496                .into(),
497            (2, 2) => (
498                "Mailbox full",
499                concat!(
500                    "The mailbox is full because the user has exceeded ",
501                    "a per-mailbox administrative quota or physical cap",
502                    "acity. The general semantics implies that the reci",
503                    "pient can delete messages to make more space avail",
504                    "able. This code should be used as a persistent tra",
505                    "nsient failure."
506                ),
507            )
508                .into(),
509            (2, 3) => (
510                "Message length exceeds administrative limit",
511                concat!(
512                    "A per-mailbox administrative message length limit ",
513                    "has been exceeded. This status code should be used",
514                    " when the per-mailbox message length limit is less",
515                    " than the general system limit. This code should b",
516                    "e used as a permanent failure."
517                ),
518            )
519                .into(),
520            (2, 4) => (
521                "Mailing list expansion problem",
522                concat!(
523                    "The mailbox is a mailing list address and the mail",
524                    "ing list was unable to be expanded. This code may ",
525                    "represent a permanent failure or a persistent tran",
526                    "sient failure."
527                ),
528            )
529                .into(),
530            (3, 0) => (
531                "Other or undefined mail system status",
532                concat!(
533                    "The destination system exists and normally accepts",
534                    " mail, but something about the system has caused t",
535                    "he generation of this DSN."
536                ),
537            )
538                .into(),
539            (3, 1) => (
540                "Mail system full",
541                concat!(
542                    "Mail system storage has been exceeded. The general",
543                    " semantics imply that the individual recipient may",
544                    " not be able to delete material to make room for a",
545                    "dditional messages."
546                ),
547            )
548                .into(),
549            (3, 2) => (
550                "System not accepting network messages",
551                concat!(
552                    "The host on which the mailbox is resident is not a",
553                    "ccepting messages. Examples of such conditions inc",
554                    "lude an imminent shutdown, excessive load, or syst",
555                    "em maintenance."
556                ),
557            )
558                .into(),
559            (3, 3) => (
560                "System not capable of selected features",
561                concat!(
562                    "Selected features specified for the message are no",
563                    "t supported by the destination system. This can oc",
564                    "cur in gateways when features from one domain cann",
565                    "ot be mapped onto the supported feature in another",
566                    "."
567                ),
568            )
569                .into(),
570            (3, 4) => (
571                "Message too big for system",
572                concat!(
573                    "The message is larger than per-message size limit.",
574                    " This limit may either be for physical or administ",
575                    "rative reasons."
576                ),
577            )
578                .into(),
579            (3, 5) => (
580                "System incorrectly configured",
581                concat!(
582                    "The system is not configured in a manner that will",
583                    " permit it to accept this message."
584                ),
585            )
586                .into(),
587            (3, 6) => (
588                "Requested priority was changed",
589                concat!(
590                    "The message was accepted for relay/delivery, but t",
591                    "he requested priority (possibly the implied defaul",
592                    "t) was not honoured. The human readable text after",
593                    " the status code contains the new priority, follow",
594                    "ed by SP (space) and explanatory human readable te",
595                    "xt."
596                ),
597            )
598                .into(),
599            (4, 0) => (
600                "Other or undefined network or routing status",
601                concat!(
602                    "Something went wrong with the networking, but it i",
603                    "s not clear what the problem is, or the problem ca",
604                    "nnot be well expressed with any of the other provi",
605                    "ded detail codes."
606                ),
607            )
608                .into(),
609            (4, 1) => (
610                "No answer from host",
611                concat!(
612                    "The outbound connection attempt was not answered, ",
613                    "because either the remote system was busy, or was ",
614                    "unable to take a call."
615                ),
616            )
617                .into(),
618            (4, 2) => (
619                "Bad connection",
620                concat!(
621                    "The outbound connection was established, but was u",
622                    "nable to complete the message transaction, either ",
623                    "because of time-out, or inadequate connection qual",
624                    "ity."
625                ),
626            )
627                .into(),
628            (4, 3) => (
629                "Directory server failure",
630                concat!(
631                    "The network system was unable to forward the messa",
632                    "ge, because a directory server was unavailable. Th",
633                    "e inability to connect to an Internet DNS server i",
634                    "s one example of the directory server failure erro",
635                    "r."
636                ),
637            )
638                .into(),
639            (4, 4) => (
640                "Unable to route",
641                concat!(
642                    "The mail system was unable to determine the next h",
643                    "op for the message because the necessary routing i",
644                    "nformation was unavailable from the directory serv",
645                    "er. A DNS lookup returning only an SOA (Start of A",
646                    "dministration) record for a domain name is one exa",
647                    "mple of the unable to route error."
648                ),
649            )
650                .into(),
651            (4, 5) => (
652                "Mail system congestion",
653                concat!(
654                    "The mail system was unable to deliver the message ",
655                    "because the mail system was congested."
656                ),
657            )
658                .into(),
659            (4, 6) => (
660                "Routing loop detected",
661                concat!(
662                    "A routing loop caused the message to be forwarded ",
663                    "too many times, either because of incorrect routin",
664                    "g tables or a user- forwarding loop."
665                ),
666            )
667                .into(),
668            (4, 7) => (
669                "Delivery time expired",
670                concat!(
671                    "The message was considered too old by the rejectin",
672                    "g system, either because it remained on that host ",
673                    "too long or because the time-to-live value specifi",
674                    "ed by the sender of the message was exceeded. If p",
675                    "ossible, the code for the actual problem found whe",
676                    "n delivery was attempted should be returned rather",
677                    " than this code."
678                ),
679            )
680                .into(),
681            (5, 0) => (
682                "Other or undefined protocol status",
683                concat!(
684                    "Something was wrong with the protocol necessary to",
685                    " deliver the message to the next hop and the probl",
686                    "em cannot be well expressed with any of the other ",
687                    "provided detail codes."
688                ),
689            )
690                .into(),
691            (5, 1) => (
692                "Invalid command",
693                concat!(
694                    "A mail transaction protocol command was issued whi",
695                    "ch was either out of sequence or unsupported."
696                ),
697            )
698                .into(),
699            (5, 2) => (
700                "Syntax error",
701                concat!(
702                    "A mail transaction protocol command was issued whi",
703                    "ch could not be interpreted, either because the sy",
704                    "ntax was wrong or the command is unrecognized."
705                ),
706            )
707                .into(),
708            (5, 3) => (
709                "Too many recipients",
710                concat!(
711                    "More recipients were specified for the message tha",
712                    "n could have been delivered by the protocol. This ",
713                    "error should normally result in the segmentation o",
714                    "f the message into two, the remainder of the recip",
715                    "ients to be delivered on a subsequent delivery att",
716                    "empt. It is included in this list in the event tha",
717                    "t such segmentation is not possible."
718                ),
719            )
720                .into(),
721            (5, 4) => (
722                "Invalid command arguments",
723                concat!(
724                    "A valid mail transaction protocol command was issu",
725                    "ed with invalid arguments, either because the argu",
726                    "ments were out of range or represented unrecognize",
727                    "d features."
728                ),
729            )
730                .into(),
731            (5, 5) => (
732                "Wrong protocol version",
733                concat!(
734                    "A protocol version mis-match existed which could n",
735                    "ot be automatically resolved by the communicating ",
736                    "parties."
737                ),
738            )
739                .into(),
740            (5, 6) => (
741                "Authentication Exchange line is too long",
742                concat!(
743                    "This enhanced status code SHOULD be returned when ",
744                    "the server fails the AUTH command due to the clien",
745                    "t sending a [BASE64] response which is longer than",
746                    " the maximum buffer size available for the current",
747                    "ly selected SASL mechanism."
748                ),
749            )
750                .into(),
751            (6, 0) => (
752                "Other or undefined media error",
753                concat!(
754                    "Something about the content of a message caused it",
755                    " to be considered undeliverable and the problem ca",
756                    "nnot be well expressed with any of the other provi",
757                    "ded detail codes."
758                ),
759            )
760                .into(),
761            (6, 1) => (
762                "Media not supported",
763                concat!(
764                    "The media of the message is not supported by eithe",
765                    "r the delivery protocol or the next system in the ",
766                    "forwarding path."
767                ),
768            )
769                .into(),
770            (6, 2) => (
771                "Conversion required and prohibited",
772                concat!(
773                    "The content of the message must be converted befor",
774                    "e it can be delivered and such conversion is not p",
775                    "ermitted. Such prohibitions may be the expression ",
776                    "of the sender in the message itself or the policy ",
777                    "of the sending host."
778                ),
779            )
780                .into(),
781            (6, 3) => (
782                "Conversion required but not supported",
783                concat!(
784                    "The message content must be converted in order to ",
785                    "be forwarded but such conversion is not possible o",
786                    "r is not practical by a host in the forwarding pat",
787                    "h. This condition may result when an ESMTP gateway",
788                    " supports 8bit transport but is not able to downgr",
789                    "ade the message to 7 bit as required for the next ",
790                    "hop."
791                ),
792            )
793                .into(),
794            (6, 4) => (
795                "Conversion with loss performed",
796                concat!(
797                    "This is a warning sent to the sender when message ",
798                    "delivery was successfully but when the delivery re",
799                    "quired a conversion in which some data was lost. T",
800                    "his may also be a permanent error if the sender ha",
801                    "s indicated that conversion with loss is prohibite",
802                    "d for the message."
803                ),
804            )
805                .into(),
806            (6, 5) => (
807                "Conversion Failed",
808                concat!(
809                    "A conversion was required but was unsuccessful. Th",
810                    "is may be useful as a permanent or persistent temp",
811                    "orary notification."
812                ),
813            )
814                .into(),
815            (6, 6) => (
816                "Message content not available",
817                concat!(
818                    "The message content could not be fetched from a re",
819                    "mote system. This may be useful as a permanent or ",
820                    "persistent temporary notification."
821                ),
822            )
823                .into(),
824            (6, 7) => (
825                "Non-ASCII addresses not permitted for that sender/recipient",
826                concat!(
827                    "This indicates the reception of a MAIL or RCPT com",
828                    "mand that non-ASCII addresses are not permitted"
829                ),
830            )
831                .into(),
832            (6, 8 | 10) => (
833                "UTF-8 string reply is required, but not permitted by the SMTP client",
834                concat!(
835                    "This indicates that a reply containing a UTF-8 str",
836                    "ing is required to show the mailbox name, but that",
837                    " form of response is not permitted by the SMTP cli",
838                    "ent."
839                ),
840            )
841                .into(),
842            (6, 9) => (
843                concat!(
844                    "UTF-8 header message cannot be transferred to ",
845                    "one or more recipients, so the message must be rejected"
846                ),
847                concat!(
848                    "This indicates that transaction failed after the f",
849                    "inal \".\" of the DATA command."
850                ),
851            )
852                .into(),
853            (7, 0) => (
854                "Other or undefined security status",
855                concat!(
856                    "Something related to security caused the message t",
857                    "o be returned, and the problem cannot be well expr",
858                    "essed with any of the other provided detail codes.",
859                    " This status code may also be used when the condit",
860                    "ion cannot be further described because of securit",
861                    "y policies in force."
862                ),
863            )
864                .into(),
865            (7, 1) => (
866                "Delivery not authorized, message refused",
867                concat!(
868                    "The sender is not authorized to send to the destin",
869                    "ation. This can be the result of per-host or per-r",
870                    "ecipient filtering. This memo does not discuss the",
871                    " merits of any such filtering, but provides a mech",
872                    "anism to report such."
873                ),
874            )
875                .into(),
876            (7, 2) => (
877                "Mailing list expansion prohibited",
878                concat!(
879                    "The sender is not authorized to send a message to ",
880                    "the intended mailing list."
881                ),
882            )
883                .into(),
884            (7, 3) => (
885                "Security conversion required but not possible",
886                concat!(
887                    "A conversion from one secure messaging protocol to",
888                    " another was required for delivery and such conver",
889                    "sion was not possible."
890                ),
891            )
892                .into(),
893            (7, 4) => (
894                "Security features not supported",
895                concat!(
896                    "A message contained security features such as secu",
897                    "re authentication that could not be supported on t",
898                    "he delivery protocol."
899                ),
900            )
901                .into(),
902            (7, 5) => (
903                "Cryptographic failure",
904                concat!(
905                    "A transport system otherwise authorized to validat",
906                    "e or decrypt a message in transport was unable to ",
907                    "do so because necessary information such as key wa",
908                    "s not available or such information was invalid."
909                ),
910            )
911                .into(),
912            (7, 6) => (
913                "Cryptographic algorithm not supported",
914                concat!(
915                    "A transport system otherwise authorized to validat",
916                    "e or decrypt a message was unable to do so because",
917                    " the necessary algorithm was not supported."
918                ),
919            )
920                .into(),
921            (7, 7) => (
922                "Message integrity failure",
923                concat!(
924                    "A transport system otherwise authorized to validat",
925                    "e a message was unable to do so because the messag",
926                    "e was corrupted or altered. This may be useful as ",
927                    "a permanent, transient persistent, or successful d",
928                    "elivery code."
929                ),
930            )
931                .into(),
932            (7, 8) => (
933                "Authentication credentials invalid",
934                concat!(
935                    "This response to the AUTH command indicates that t",
936                    "he authentication failed due to invalid or insuffi",
937                    "cient authentication credentials. In this case, th",
938                    "e client SHOULD ask the user to supply new credent",
939                    "ials (such as by presenting a password dialog box)",
940                    "."
941                ),
942            )
943                .into(),
944            (7, 9) => (
945                "Authentication mechanism is too weak",
946                concat!(
947                    "This response to the AUTH command indicates that t",
948                    "he selected authentication mechanism is weaker tha",
949                    "n server policy permits for that user. The client ",
950                    "SHOULD retry with a new authentication mechanism."
951                ),
952            )
953                .into(),
954            (7, 10) => (
955                "Encryption Needed",
956                concat!(
957                    "This indicates that external strong privacy layer ",
958                    "is needed in order to use the requested authentica",
959                    "tion mechanism. This is primarily intended for use",
960                    " with clear text authentication mechanisms. A clie",
961                    "nt which receives this may activate a security lay",
962                    "er such as TLS prior to authenticating, or attempt",
963                    " to use a stronger mechanism."
964                ),
965            )
966                .into(),
967            (7, 11) => (
968                "Encryption required for requested authentication mechanism",
969                concat!(
970                    "This response to the AUTH command indicates that t",
971                    "he selected authentication mechanism may only be u",
972                    "sed when the underlying SMTP connection is encrypt",
973                    "ed. Note that this response code is documented her",
974                    "e for historical purposes only. Modern implementat",
975                    "ions SHOULD NOT advertise mechanisms that are not ",
976                    "permitted due to lack of encryption, unless an enc",
977                    "ryption layer of sufficient strength is currently ",
978                    "being employed."
979                ),
980            )
981                .into(),
982            (7, 12) => (
983                "A password transition is needed",
984                concat!(
985                    "This response to the AUTH command indicates that t",
986                    "he user needs to transition to the selected authen",
987                    "tication mechanism. This is typically done by auth",
988                    "enticating once using the [PLAIN] authentication m",
989                    "echanism. The selected mechanism SHOULD then work ",
990                    "for authentications in subsequent sessions."
991                ),
992            )
993                .into(),
994            (7, 13) => (
995                "User Account Disabled",
996                concat!(
997                    "Sometimes a system administrator will have to disa",
998                    "ble a user's account (e.g., due to lack of payment",
999                    ", abuse, evidence of a break-in attempt, etc). Thi",
1000                    "s error code occurs after a successful authenticat",
1001                    "ion to a disabled account. This informs the client",
1002                    " that the failure is permanent until the user cont",
1003                    "acts their system administrator to get the account",
1004                    " re-enabled. It differs from a generic authenticat",
1005                    "ion failure where the client's best option is to p",
1006                    "resent the passphrase entry dialog in case the use",
1007                    "r simply mistyped their passphrase."
1008                ),
1009            )
1010                .into(),
1011            (7, 14) => (
1012                "Trust relationship required",
1013                concat!(
1014                    "The submission server requires a configured trust ",
1015                    "relationship with a third-party server in order to",
1016                    " access the message content. This value replaces t",
1017                    "he prior use of X.7.8 for this error condition. th",
1018                    "ereby updating [RFC4468]."
1019                ),
1020            )
1021                .into(),
1022            (7, 15) => (
1023                "Priority Level is too low",
1024                concat!(
1025                    "The specified priority level is below the lowest p",
1026                    "riority acceptable for the receiving SMTP server. ",
1027                    "This condition might be temporary, for example the",
1028                    " server is operating in a mode where only higher p",
1029                    "riority messages are accepted for transfer and del",
1030                    "ivery, while lower priority messages are rejected."
1031                ),
1032            )
1033                .into(),
1034            (7, 16) => (
1035                "Message is too big for the specified priority",
1036                concat!(
1037                    "The message is too big for the specified priority.",
1038                    " This condition might be temporary, for example th",
1039                    "e server is operating in a mode where only higher ",
1040                    "priority messages below certain size are accepted ",
1041                    "for transfer and delivery."
1042                ),
1043            )
1044                .into(),
1045            (7, 17) => (
1046                "Mailbox owner has changed",
1047                concat!(
1048                    "This status code is returned when a message is rec",
1049                    "eived with a Require-Recipient-Valid-Since field o",
1050                    "r RRVS extension and the receiving system is able ",
1051                    "to determine that the intended recipient mailbox h",
1052                    "as not been under continuous ownership since the s",
1053                    "pecified date-time."
1054                ),
1055            )
1056                .into(),
1057            (7, 18) => (
1058                "Domain owner has changed",
1059                concat!(
1060                    "This status code is returned when a message is rec",
1061                    "eived with a Require-Recipient-Valid-Since field o",
1062                    "r RRVS extension and the receiving system wishes t",
1063                    "o disclose that the owner of the domain name of th",
1064                    "e recipient has changed since the specified date-t",
1065                    "ime."
1066                ),
1067            )
1068                .into(),
1069            (7, 19) => (
1070                "RRVS test cannot be completed",
1071                concat!(
1072                    "This status code is returned when a message is rec",
1073                    "eived with a Require-Recipient-Valid-Since field o",
1074                    "r RRVS extension and the receiving system cannot c",
1075                    "omplete the requested evaluation because the requi",
1076                    "red timestamp was not recorded. The message origin",
1077                    "ator needs to decide whether to reissue the messag",
1078                    "e without RRVS protection."
1079                ),
1080            )
1081                .into(),
1082            (7, 20) => (
1083                "No passing DKIM signature found",
1084                concat!(
1085                    "This status code is returned when a message did no",
1086                    "t contain any passing DKIM signatures. (This viola",
1087                    "tes the advice of Section 6.1 of [RFC6376].)"
1088                ),
1089            )
1090                .into(),
1091            (7, 21) => (
1092                "No acceptable DKIM signature found",
1093                concat!(
1094                    "This status code is returned when a message contai",
1095                    "ns one or more passing DKIM signatures, but none a",
1096                    "re acceptable. (This violates the advice of Sectio",
1097                    "n 6.1 of [RFC6376].)"
1098                ),
1099            )
1100                .into(),
1101            (7, 22) => (
1102                "No valid author-matched DKIM signature found",
1103                concat!(
1104                    "This status code is returned when a message contai",
1105                    "ns one or more passing DKIM signatures, but none a",
1106                    "re acceptable because none have an identifier(s) t",
1107                    "hat matches the author address(es) found in the Fr",
1108                    "om header field. This is a special case of X.7.21.",
1109                    " (This violates the advice of Section 6.1 of [RFC6",
1110                    "376].)"
1111                ),
1112            )
1113                .into(),
1114            (7, 23) => (
1115                "SPF validation failed",
1116                concat!(
1117                    "This status code is returned when a message comple",
1118                    "ted an SPF check that produced a \"fail\" result, ",
1119                    "contrary to local policy requirements. Used in pla",
1120                    "ce of 5.7.1 as described in Section 8.4 of [RFC720",
1121                    "8]."
1122                ),
1123            )
1124                .into(),
1125            (7, 24) => (
1126                "SPF validation error",
1127                concat!(
1128                    "This status code is returned when evaluation of SP",
1129                    "F relative to an arriving message resulted in an e",
1130                    "rror. Used in place of 4.4.3 or 5.5.2 as described",
1131                    " in Sections 8.6 and 8.7 of [RFC7208]."
1132                ),
1133            )
1134                .into(),
1135            (7, 25) => (
1136                "Reverse DNS validation failed",
1137                concat!(
1138                    "This status code is returned when an SMTP client's",
1139                    " IP address failed a reverse DNS validation check,",
1140                    " contrary to local policy requirements."
1141                ),
1142            )
1143                .into(),
1144            (7, 26) => (
1145                "Multiple authentication checks failed",
1146                concat!(
1147                    "This status code is returned when a message failed",
1148                    " more than one message authentication check, contr",
1149                    "ary to local policy requirements. The particular m",
1150                    "echanisms that failed are not specified."
1151                ),
1152            )
1153                .into(),
1154            (7, 27) => (
1155                "Sender address has null MX",
1156                concat!(
1157                    "This status code is returned when the associated s",
1158                    "ender address has a null MX, and the SMTP receiver",
1159                    " is configured to reject mail from such sender (e.",
1160                    "g., because it could not return a DSN)."
1161                ),
1162            )
1163                .into(),
1164            (7, 28) => (
1165                "Mail flood detected",
1166                concat!(
1167                    "The message appears to be part of a mail flood of ",
1168                    "similar abusive messages."
1169                ),
1170            )
1171                .into(),
1172            (7, 29) => (
1173                "ARC validation failure",
1174                concat!(
1175                    "This status code may be returned when a message fa",
1176                    "ils ARC validation."
1177                ),
1178            )
1179                .into(),
1180            (7, 30) => (
1181                "REQUIRETLS support required",
1182                concat!(
1183                    "This indicates that the message was not able to be",
1184                    " forwarded because it was received with a REQUIRET",
1185                    "LS requirement and none of the SMTP servers to whi",
1186                    "ch the message should be forwarded provide this su",
1187                    "pport."
1188                ),
1189            )
1190                .into(),
1191            _ => None,
1192        }
1193    }
1194}