\section{Using SMTP}\label{sec:smtp} % \begin{description} \item[Used files:] smtp.scm \item[Name of the package:] smtp \end{description} % \subsection{Philosophy} SMTP protocol procedures tend to return two values: \begin{description} \item{\semvar{code}} The integer SMTP reply code returned by server for the transaction. \item{\semvar{text}} A list of strings -- the text messages tagged by the code. \end{description} The text strings have the initial code numerals and the terminating \ex{CR}/\ex{LF}'s stripped. Codes in the range $[1,399]$ are sucess codes; codes in the range $[400,599]$ are error codes; codes $>= 600$ are not part of the official SMTP spec. This module uses codes $>= 600$ to indicate extra-protocol errors. There are two of these: \begin{description} \item{600 Server reply could not be parsed.} The server sent back some sort of incomprehensible garbage reply. \item{621 Premature EOF while reading server reply.} The server shut down in the middle of a reply. \end{description} A list of the official protocol return codes can be seen in table \ref{smtp-reply-codes}. \subsection{Procedures} \begin{defundesc}{sendmail}{to-list body \ovar{host}}{code text-list} Mail message \semvar{body} to recipients in list \semvar{to-list}. Message handed off to server running on \semvar{host}; default is the local host. Returns two values: \semvar{code} and \semvar{text-list}, i.e. the code returned by the server and the text-message, seperated by lines. However, if some recipients were rejected, sendmail sends to the rest of the recipients, and the partial-success return is [700 \semvar{loser-alist}] where \semvar{loser-alist} is a list whose elements are of the form \ex{(\semvar{loser-recipient} \semvar{code} . \semvar{text})} -- that is, for each recipient refused by the server, you get the error data sent back for that guy. The success check is \ex{(< code 400)}. \end{defundesc} \begin{defundesc}{\%sendmail}{from local-host to dest-host message}{code text} Mail \semvar{message} to recipient \semvar{to} using \semvar{dest-host}, telling \semvar{from} as your mail-address and \semvar{local-host} as your system-name. \end{defundesc} \defun{expn}{name host}{code text} \defunx{vrfy}{name host}{code text} \defunx{mail-help}{host \ovar{details}}{code text-list} \begin{desc} These three are simple queries of the server as stated in the RFC~821: \ex{expn} asks the server to confirm that the argument identifies a mailing list, and if so, to return the membership of that list. The full name of the users (if known) and the fully specified mailboxes are returned in a multiline reply. \ex{vrfy} asks the receiver to confirm that the argument identifies a user. If it is a user name, the full name of the user (if known) and the fully specified mailbox are returned. \ex{mail-help} causes the server to send helpful information. The command may take an argument (\semvar{details}) (e.g., any command name) and return more specific information as a response. \end{desc} \dfn{smtp-transactions}{socket ?transaction1 ...}{code text-list}{syntax} \dfnx{smtp-transactions/no-close}{socket ?transaction1 ...}{code text-list}{syntax} \begin{desc} These macros make it easy to do simple sequences of SMTP commands. Evaluate a series of expressions \semvar{?transaction1}, \semvar{?transaction2}, \ldots \begin{itemize} \item Each expression should perform an SMTP transaction, and return two values: \semvar{code} (the integer reply code) and \semvar{text} (list of strings that came with the reply). \item If the transaction's reply code is 221 or 421 (meaning the socket has been closed), then the transaction sequence is is aborted, and the \ex{smtp\=trans\ob{}actions} form returns the \semvar{code} and \semvar{text} values for the current transaction. \item If the reply code is an error code (in the four- or five-hundred range), the transaction sequence is aborted, and the fatal transaction's \semvar{code} and \semvar{text} values are returned. \ex{smtp\=trans\ob{}actions} will additionally close the socket for you; \ex{smtp-trans\ob{}actions/\ob{}no\=close} will not. \item If the transaction is the last in the transaction sequence, its \semvar{code} and \semvar{text} values are returned. \item Otherwise, we throw away the current \semvar{code} and \semvar{text} values, and proceed to the next transaction. \end{itemize} Since \ex{smtp-trans\ob{}actions} closes the socket whenever it aborts a sequence, an \ex{smtp-trans\ob{}actions} form terminated with an \ex{(smtp/\ob{}quit socket)} transaction will always close the socket. If the socket should be kept open in the case of an abort, use \ex{smtp-trans\ob{}actions/\ob{}no\=close}. We abort sequences if a transaction results in a 400-class error code. So, a sequence mailing a message to five people, with 5 RCPT's, would abort if the mailing address for one of these people was wrong, rather than proceeding to mail the other four. This may not be what you want; if so, you'll have to roll your own. \end{desc} \defun{smtp/open}{host \ovar{maybe-port}}{socket} \defunx{smtp/helo}{local-host-name}{code text-list} \defunx{smtp/mail}{sender-address}{code text-list} \defunx{smtp/rcpt}{destination-address}{code text-list} \defunx{smtp/data}{socket message}{code text-list} \defunx{smtp/send}{sender-address}{code text-list} \defunx{smtp/soml}{sender-address}{code text-list} \defunx{smtp/saml}{sender-address}{code text-list} \defunx{smtp/rset}{}{code text-list} \defunx{smtp/vrfy}{user}{code text-list} \defunx{smtp/expn}{user}{code text-list} \defunx{smtp/help}{details}{code text-list} \defunx{smtp/noop}{}{code text-list} \defunx{smtp/quit}{socket}{code text-list} \defunx{smtp/turn}{}{code text-list} \begin{desc} These functions implement the basics of the protocol, i.e. they send the corresponding command along with the argument(s), if any. A short look to the code of \ex{\%sendmail} will give you the basics on how to use the commands. You will obtain further informations in the RFC~821. \semvar{host}, \semvar{local-host}, \semvar{sender-address}, \semvar{destination-address}, \semvar{user} and \semvar{details} are strings, \semvar{message} may be a string or an input-port. \semvar{socket} is a socket, mostly one returned by \ex{smtp/\ob{}open}. \end{desc} \begin{defundesc}{handle-smtp-reply}{socket}{code text-list} Read and handle the reply. Return an integer (the reply \semvar{code}), and a list of the text lines (\semvar{text-list}) that came tagged by the reply code. The text lines have the reply-code prefix (first 4 chars) and the terminating cr/lf's stripped. \end{defundesc} \begin{defundesc}{read-smtp-reply}{port}{code text-list} Read a reply from the SMTP server. Returns two values: \begin{description} \item{\semvar{code}} Integer. The reply code. \item{\semvar{text}} String list. A list of the text lines comprising the reply. Each line of text is stripped of the initial reply-code numerals (e.g., the first four chars of the reply), and the trailing cr/lf. We are in fact generous about what we take to be a line -- the protocol requires cr/lf terminators, but we'll accept just lf. This appears to true to the spirit of the "be strict in what you send, and generous in what you accept" Internet protocol philosphy. \end{description} \end{defundesc} \begin{defundesc}{parse-smtp-reply}{line}{code rest more?} Parse a line of SMTP reply. Return three values: \begin{description} \item{\semvar{code}} integer -- the reply code that prefixes the string. \item{\semvar{rest}} string -- the rest of the line. \item{\semvar{more?}} boolean -- is there more reply to read (i.e., was the numeric reply code terminated by a ``\ex{-}'' character?) \end{description} \end{defundesc} \begin{defundesc}{smtp-stuff}{text pchar}{stuffed-string last-char} The message body of a piece of email is terminated by the sequence \ex{ }, i.e. end-of-line, period, end-of-line. If the message body contains this magic sequence, it has to be escaped. We do this by mapping the sequence \ex{ } to \ex{ }; the SMTP receiver undoes this mapping. \semvar{text} is a string to stuff, \semvar{pchar} was the character read just before \semvar{text} (which matters if it is a line-feed). If \semvar{text} is the first chunk of the entire msg, then \semvar{pchar} can be \sharpf. Return two values: the \semvar{stuffed-string}, and the last char in \semvar{text} (or \semvar{pchar} if \semvar{text} is empty). The last-char value returned can be used as the \semvar{pchar} arg for the following call to \ex{smtp\=stuff}. \end{defundesc} \subsection{Additional information about SMTP} \subsubsection*{Reply codes} This material is taken from the RFC. The first digits encode categories of responses: \begin{description} \item{\bfseries 1yz Positive Preliminary reply\,} The command has been accepted, but the requested action is being held in abeyance, pending confirmation of the information in this reply. The sender-SMTP should send another command specifying whether to continue or abort the action. \begin{leftinset} Note: SMTP does not have any commands that allow this type of reply, and so does not have the continue or abort commands. \end{leftinset} \item{\bfseries 2yz Positive Completion reply\,} The requested action has been successfully completed. A new request may be initiated. \item{\bfseries 3yz Positive Intermediate reply\,} The command has been accepted, but the requested action is being held in abeyance, pending receipt of further information. The sender-SMTP should send another command specifying this information. This reply is used in command sequence groups. \item{\bfseries 4yz Transient Negative Completion reply\,} The command was not accepted and the requested action did not occur. However, the error condition is temporary and the action may be requested again. The sender should return to the beginning of the command sequence (if any). It is difficult to assign a meaning to ``transient'' when two different sites (receiver- and sender- SMTPs) must agree on the interpretation. Each reply in this category might have a different time value, but the sender-SMTP is encouraged to try again. A rule of thumb to determine if a reply fits into the 4yz or the 5yz category (see below) is that replies are 4yz if they can be repeated without any change in command form or in properties of the sender or receiver. (E.g., the command is repeated identically and the receiver does not put up a new implementation.) \item{\bfseries 5yz Permanent Negative Completion reply\,} The command was not accepted and the requested action did not occur. The sender-SMTP is discouraged from repeating the exact request (in the same sequence). Even some ``permanent'' error conditions can be corrected, so the human user may want to direct the sender-SMTP to reinitiate the command sequence by direct action at some point in the future (e.g., after the spelling has been changed, or the user has altered the account status). \end{description} The second digit encodes responses in specific categories: \begin{description} \item{\bfseries x0z Syntax\,} These replies refer to syntax errors, syntactically correct commands that don't fit any functional category, and unimplemented or superfluous commands. \item{\bfseries x1z Information\,} These are replies to requests for information, such as status or help. \item{\bfseries x2z Connections\,} These are replies referring to the transmission channel. \item{\bfseries x3z\,} Unspecified as yet. \item{\bfseries x4z\,} Unspecified as yet. \item{\bfseries x5z Mail system\,} These replies indicate the status of the receiver mail system vis-a-vis the requested transfer or other mail system action. \end{description} \begin{table} \label{smtp-reply-codes} \begin{tabular}{|lp{10cm}|} \hline 500 & Syntax error, command unrecognized \newline [This may include errors such as command line too long] \\ 501 & Syntax error in parameters or arguments \\ 502 & Command not implemented\\ 503 & Bad sequence of commands\\ 504 & Command parameter not implemented\\ \hline 211 & System status, or system help reply\\ 214 & Help message \newline [Information on how to use the receiver or the meaning of a particular non-standard command; this reply is useful only to the human user]\\ \hline 220 & \semvar{domain} Service ready \\ 221 & \semvar{domain} Service closing transmission channel\\ 421 & \semvar{domain} Service not available, closing transmission channel\newline [This may be a reply to any command if the service knows it must shut down]\\ \hline 250 & Requested mail action okay, completed\\ 251 & User not local; will forward to \semvar{forward-path}\\ 450 & Requested mail action not taken: mailbox unavailable [E.g., mailbox busy]\\ 550 & Requested action not taken: mailbox unavailable [E.g., mailbox not found, no access]\\ 451 & Requested action aborted: error in processing\\ 551 & User not local; please try \semvar{forward-path}\\ 452 & Requested action not taken: insufficient system storage\\ 552 & Requested mail action aborted: exceeded storage allocation\\ 553 & Requested action not taken: mailbox name not allowed [E.g., mailbox syntax incorrect]\\ 354 & Start mail input; end with \ex{CRLF}.\ex{CRLF}\\ 554 & Transaction failed\\ \hline \end{tabular} \caption{Complete list of SMPT reply-codes.} \end{table} \begin{table} \label{smtp-command-reply-codes} \begin{tabular}{|p{2.3cm}||p{2.3cm}|p{2.3cm}|p{2.3cm}|p{2.3cm}|} \hline \bf{What} & \bf{intermediate} & \bf{success} & \bf{failure} & \bf{error}\\ \hline \hline conn. establ. & & 220 & 421 &\\ HELO & & 250 & & 500, 501, 504, 421\\ MAIL & & 250 & 552, 451, 452 & 500, 501, 421\\ RCPT & & 250, 251 & 550, 551, 552, 553, 450, 451, 452 & 500, 501, 503, 421\\ DATA & 354 \verb|->| data & 250 & 552, 554, 451, 452 & \\ & otherwise & & 451, 554 & 500, 501, 503, 421\\ RSET & & 250 & & 500, 501, 504, 421\\ SEND & & 250 & 552, 451, 452 & 500, 501, 502, 421\\ SOML & & 250 & 552, 451, 452 & 500, 501, 502, 421\\ SAML & & 250 & 552, 451, 452 & 500, 501, 502, 421\\ VRFY & & 250, 251 & 550, 551, 553 & 500, 501, 502, 504, 421\\ EXPN & & 250 & 550 & 500, 501, 502, 504, 421\\ HELP & & 211, 214 & & 500, 501, 502, 504, 421\\ NOOP & & 250 & & 500, 421\\ QUIT & & 221 & & 500\\ TURN & & 250 & 502 & 500, 503\\ \hline \end{tabular} \caption{command--reply sequences.} \end{table} %%% Local Variables: %%% mode: latex %%% TeX-master: t %%% End: