Reasonably complete and up-to-date documentation.

This commit is contained in:
sperber 2003-01-21 15:54:02 +00:00
parent b60335d2cd
commit b2c4e59cb8
1 changed files with 96 additions and 356 deletions

View File

@ -1,374 +1,114 @@
\chapter{Using SMTP}\label{cha:smtp}
%
\begin{description}
\item[Used files:] smtp.scm
\item[Name of the package:] smtp
\end{description}
\chapter{SMTP Client}\label{cha:smtp}
%
The \ex{smtp} structure provides an client library for the Simple Mail
Transfer Protocol, commonly used for sending email on the Internet.
This library provides a simple wrapper for sending complete emails as
well as procedures for composing custom SMTP transactions.
\section{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 procedures described here usually return an SMTP reply code. For
details, see RFC~821.
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:
\defun{smtp-send-mail}{from to-list headers body [host]}{code list}
\begin{desc}
This emails message \var{body} with hedaers \var{headers} to
recipients in list \var{to-list}, using a sender address \var{from}.
The email is handed off to the SMTP server running on \var{host};
default is the local host. \var{Body} is either a list of strings
representing the lines of the message body or an input port which is
exhausted to determine the message body. \var{Headers} is an
association lists, mapping symbols representing RFC~822 field names
to strings representing field bodies.
This returns two values: \var{code} and \var{list}, the code
returned by the server and the text message, represented as a list
lines. If some recipients were rejected, \ex{smtp-send-mail} sends
to the rest of the recipients, and returns code 700 and an
association list whose elements are of the form
\ex{(\var{loser-recipient} \var{code} . \var{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{desc}
\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}.
\section{Procedures}
\begin{defundesc}{sendmail}{to-list body [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 [details]}{code text-list}
\defun{smtp-expand}{name host}{code text}
\defunx{smtp-verify}{name host}{code text}
\defunx{smtp-get-help}{host [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.
RFC~821: \ex{smtp-expann} 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{Smtp-verify} 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{Smtp-get-help} causes the server to send helpful information.
The command may take an argument (\var{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}
\defun{smtp-connect}{host [port]}{smtp-connection}
\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.
\ex{Smtp-connect} returns an SMTP connection value that represents
a connection to the SMTP server.
\end{desc}
\defun{smtp/open}{host [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}
\defun{smtp-transactions}{smtp-connection transaction1 ...}{code text-list}
\defunx{smtp-transactions/no-close}{smtp-connection transaction1 ...}{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}
These procedures make it easy to do simple sequences of SMTP
commands. \var{Smtp-connection} must be an SMTP connection as
returned by \ex{smtp-connect}. The \var{transaction} arguments must
be transactions as returned by the procedures below.
\ex{Smtp-transactions} and \ex{smtp-transactions/no-close} execute
the transactions specified by the arguments.
\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{<CRLF> <period> <CRLF>}, 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{<LF>
<period>} to \ex{<lf> <period> <period>}; the SMTP receiver undoes
this mapping.
For each transaction,
\begin{itemize}
\item If the transaction's reply code is 221 or 421 (meaning the socket has
been closed), then the transaction sequence is aborted, and
\ex{smtp-transactions}/\ex{smtp-transactions/no-close} return the
reply code and text from that 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 code
and text values are returned. \ex{Smtp-transactions} will additionally
close the socket for you; \ex{smtp-transactions/no-close} will not.
\item If the transaction is the last in the transaction sequence,
its reply code and text are returned.
\item Otherwise, we throw away the current reply code and text, and
proceed to the next transaction.
\end{itemize}
%
\ex{Smtp-transactions} closes the socket after the transaction. (The
\ex{smtp-quit} transaction, when executed, also closes the transaction.)
\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}
If the socket should be kept open in the case of an abort, use
\ex{Smtp-transactions/no-close}.
\end{desc}
\section{Additional information about SMTP}
\section{Reply codes}
This material is taken from the RFC. The first digits encode categories
of responses:
\begin{description}
\item[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[2yz Positive Completion reply\,] The requested action has
been successfully completed. A new request may be initiated.
\item[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[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[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[x0z Syntax\,] These replies refer to syntax errors,
syntactically correct commands that don't fit any functional
category, and unimplemented or superfluous commands.
\item[x1z Information\,] These are replies to requests for
information, such as status or help.
\item[x2z Connections\,] These are replies referring to the
transmission channel.
\item[x3z\,] Unspecified as yet.
\item[x4z\,] Unspecified as yet.
\item[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}
\begin{center}
\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 SMTP reply-codes.}
\end{center}
\end{table}
\begin{table}
\begin{center}
\label{smtp-command-reply-codes}
\begin{tabular}{|l||l|l|l|l|}
\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{center}
\end{table}
\defunx{smtp-helo}{local-host-name}{smtp-transaction}
\defunx{smtp-mail}{sender-address}{smtp-transaction}
\defunx{smtp-rcpt}{destination-address}{smtp-transaction}
\defunx{smtp-data}{socket message}{smtp-transaction}
\defunx{smtp-send}{sender-address}{smtp-transaction}
\defunx{smtp-soml}{sender-address}{smtp-transaction}
\defunx{smtp-saml}{sender-address}{smtp-transaction}
\defvarx{smtp-rset}{smtp-transaction}
\defunx{smtp-vrfy}{user}{smtp-transaction}
\defunx{smtp-expn}{user}{smtp-transaction}
\defunx{smtp-help}{details}{smtp-transaction}
\defvarx{smtp-noop}{smtp-transaction}
\defvarx{smtp-quit}{smtp-transaction}
\defvarx{smtp-turn}{smtp-transaction}
\begin{desc}
These transactions represent the commands of the SMTP protocol for
use in \ex{smtp-transactions} and \ex{smtp-transactions/no-close},
i.e.\ they send the corresponding command along with the argument(s),
if any. For details, consult RFC~821.
The \ex{smtp-quit} transaction, in addition to sending a \ex{QUIT}
command to the SMTP server, also closes the socket of its SMTP
connection.
\end{desc}
%%% Local Variables: