summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosé Fonseca <jrfonseca@users.sourceforge.net>2003-07-05 10:49:22 +0000
committerJosé Fonseca <jrfonseca@users.sourceforge.net>2003-07-05 10:49:22 +0000
commit60b9cfd5abf4e2c68821b8435cc73ec3a7d1e058 (patch)
tree8c9f64a1f99ca5eead75993b53852d3fa132a366
parent5f63162c8088321f5d0f88e8a367815b9cd2d694 (diff)
Better documentation.
Support for more sendmail options. Error verification for libESMTP calls.
-rw-r--r--Makefile.am2
-rw-r--r--NEWS50
-rw-r--r--README241
-rw-r--r--TODO14
-rw-r--r--esmtp.18
-rw-r--r--local.c17
-rw-r--r--main.c117
-rw-r--r--message.c41
-rw-r--r--message.h12
-rw-r--r--rfc822.c8
-rw-r--r--sample.esmtprc30
-rw-r--r--smtp.c226
-rw-r--r--smtp.h16
13 files changed, 554 insertions, 228 deletions
diff --git a/Makefile.am b/Makefile.am
index ea96204..2e1d798 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -19,7 +19,7 @@ esmtp_SOURCES = \
smtp.h \
xmalloc.h
-EXTRA_DIST = README.mutt sample.esmtprc
+EXTRA_DIST = sample.esmtprc
AM_YFLAGS = -d
diff --git a/NEWS b/NEWS
index 4036167..44dfae8 100644
--- a/NEWS
+++ b/NEWS
@@ -1,26 +1,42 @@
-Version 0.4 (under development)
+News
+~~~~
- * Debian packaging.
- * Fixes to compile on FreeBSD (Tim Hemel).
- * Local delivery via a MDA.
- * Extraction of the recipients from the headers ('-t' option).
+ * Version 0.4 (under development):
+ * Debian packaging.
-Version 0.3
+ * Fixes to compile on FreeBSD (Tim Hemel).
- * Capability to generate log files.
- * Better verbose output.
- * Minor bug fixes and documentation enhancements.
- * Multiple identities (Jerome).
+ * Local delivery via a MDA.
+ * Extraction of the recipients from the headers ('-t' option).
-Version 0.2:
+ * 8bit-MIME extension ('-B' option).
- * Packaging corrections.
- * Minor bug fixes and documentation enhancements.
- * Use sendmail exit codes.
-
+ * Further Delivery Status Notification ('-R' and '-V' options).
-Version 0.1:
- * Initial release
+ * Version 0.3:
+
+ * Capability to generate log files.
+
+ * Better verbose output.
+
+ * Minor bug fixes and documentation enhancements.
+
+ * Multiple identities (Jerome).
+
+
+ * Version 0.2:
+
+ * Packaging corrections.
+
+ * Minor bug fixes and documentation enhancements.
+
+ * Use sendmail exit codes.
+
+
+ * Version 0.1:
+
+ * Initial release.
+
diff --git a/README b/README
index 9caa605..1a19027 100644
--- a/README
+++ b/README
@@ -1,6 +1,237 @@
-ESMTP is a user configurable relay-only Mail Transfer Agent (MTA) with a
-sendmail-compatible syntax. It's based on libESMTP supporting the AUTH
-(including the CRAM-MD5 and NTLM SASL mechanisms) and the StartTLS SMTP
-extensions.
+ -----
+ ESMTP
+ -----
+ José Fonseca
+ ---
+ July 2003
+
+
+Introduction
+~~~~~~~~~~~~
+
+ <<esmtp>> is a user configurable relay-only Mail Transfer Agent (MTA) with a
+ <<sendmail>> compatible syntax. It's based on <<libESMTP>> supporting the
+ AUTH (including the CRAM-MD5 and NTLM SASL mechanisms) and the StartTLS SMTP
+ extensions.
+
+ See the {{{http://esmtp.sourceforge.net/}ESMTP home page}} for updated
+ information.
+
+
+Rationale
+~~~~~~~~~
+
+ Since the moment I switched to Linux I had some problems to have email
+ properly configurated to my personal needs. I use a POP3/SMTP mail account
+ for my personal mail, and I usually connect to the internet with my laptop
+ via several LANs (home, work, ...) with several different firewall
+ configurations. The standard MTAs didn't provided the flexibility I needed --
+ they either failed to deliver the mail directly or failed to authenticate
+ with the relay, or were configured system-wide and conflicted with the local
+ MTA.
+
+ <<fetchmail>> always worked fine to get email, but I needed a <<sendmail>>
+ alike program to send email from <<Mutt>>. Basically I wanted a program
+ which could be for SMTP what <<fetchmail>> was for POP3, i.e., an user
+ configurable MTA with authorization support.
+
+ Some small modifications to the <<<mail-file>>> example from <<libESMTP>> did
+ the trick. After receiving positive feedback from the <<libESMTP>> author,
+ Brian Stafford, I decided to make the program more confortable for others to
+ use -- adding a command-line option parser extracted from sendmail, a
+ configuration file parser from <<fetchmail>>, a man page based on <<ssmtp>>
+ and <<sendmail>> man pages and using autotools to wrap it all up. The result
+ of this cut and paste effort is <<esmtp>>. Well, the first version, that is.
+ Since then a few more bells and whistles were added, with the help of some
+ contributors.
+
+
+
+Configuration
+~~~~~~~~~~~~~
+
+
+* Sample configuration file
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ This is a simple configuration file for a quick start:
+
+--------------------------------------
+hostname = mail.myisp.com:25
+username = "myusername"
+password = "mysecret"
+starttls = enabled
+
+identity = myself@somewhere.com
+ hostname = smtp.somewhere.com:25
+ username = "myself"
+ password = "secret"
+ starttls = enabled
+
+mda "/usr/bin/procmail -d %T"
+--------------------------------------
+
+
+* Configuration options
+~~~~~~~~~~~~~~~~~~~~~~~
+
+ Options are speficied by giving a <keyword=value> in the configuration
+ file. The equal sign is optional and can be replaced by whitespace. The
+ value may be enclose in simple or double quotes, in which case special
+ characters can be escaped as in normal <C> strings.
+
+ [hostname] - set SMTP host and service (port).
+
+ This is specified in the format <<<host.example.org[:service]>>> with no
+ whitespace surrounding the colon if service is specified. service may be a
+ name from <<</etc/services>>> or a decimal port number. If not specified
+ the port defaults to 587.
+
+ Note (from <<libESMTP>> documentation): the default port number is set to
+ 587 since this is the port that should be used for mail submission, see RFC
+ 2476. By choosing this default now, the API does not change behaviour
+ unexpectedly in the future as use of the new standard becomes commonplace.
+ The hostport notation simplifies things for the application, the user can
+ type <<<localhost:smtp>>> or <<<localhost:25>>> where the application
+ expects a host name.
+
+ [username] - set the user name.
+
+ [password] - set the password.
+
+ [starttls] - determine the usage of the StartTLS extension.
+
+ It can be one of <"enabled">, <"disabled"> or <"required">. It defaults to
+ disabled.
+
+ [certificate_passphrase] - set the certificate passphrase.
+
+ [identity] - define an identity.
+
+ An identities is a set of options associated with a given address. For
+ example:
+
+--------------------------------------
+identity = myself@somewhere.com
+ hostname = smtp.somewhere.com:25
+ username = "myself"
+ password = "secret"
+--------------------------------------
+
+ Identities are be selected by the address specified in the <-f> flag. You
+ can have as many you like.
+
+ The options up to the first <identity> option constitute the default
+ identity.
+
+
+ Note: the default identity settings are not shared by the other identities.
+ Everything (username, password, etc.) must be specified for every identity
+ even if they don't differ from the default identity.
+
+ [mda] - set the Mail Delivery Agent (MDA).
+
+ Local delivery addresses will be inserted into the MDA command wherever you
+ place a <%T>. The mail message's From address will be inserted where you
+ place an <%F>.
+
+ Some common MDAs are <"/usr/bin/procmail -d %T">,
+ <"/usr/bin/deliver"> and <"/usr/lib/mail.local %T">.
+
+ See below for more information about using <<esmtp>> with an MDA.
+
+
+Invocation
+~~~~~~~~~~
+
+ <<esmtp>> is command line compatible with <<sendmail>>.
+
+ See the <<esmtp>> man page for information on how to invoke it.
+
+
+Interfacing to Mail User Agents
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Most Mail User Agents (MUAs) will work without need to configuration provided
+ that you install a symbolic from <<</usr/sbin/sendmail>>> to the esmtp
+ executable. This should already be taken care of by the <install> target of
+ the makefile when building from source.
+
+ If by any reason it is not possible to have (such as no administrator
+ priviledges or the use of another MTA for local delivery) then you will have
+ to reconfigure your MUA to use the esmtp executable instead.
+
+
+* Mutt
+~~~~~~
+
+ If not using a symbolic link to the esmtp executable you can make <<Mutt>> use
+ <<esmtp>> by adding the following line to your <<<~/.muttrc>>>:
+
+-----------------------------
+set sendmail="/path/to/esmtp"
+-----------------------------
+
+ <<Esmtp>> supports <<sendmail>> envelope sender <-f> flag, and you are
+ advised to always enable it by adding the following line to <<Mutt>>
+ configuration file:
+
+---------------------
+set envelope_from=yes
+---------------------
+
+ For debugging purposes you may prefer to put in your <<<~/.muttrc>>>:
+
+--------------------------------------------------
+set sendmail="/path/to/esmtp -v -X /tmp/esmtp.log"
+--------------------------------------------------
+
+ This will enable verbose output and logging of the traffic with the SMTP
+ server.
+
+
+Interfacing to Mail Delivery Agents
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ <<esmtp>> relies upon a Mail Delivery Agent (MDA) for local mail delivery, so
+ you need one if you want to avoid having another MTA for local delivery.
+
+ Notice that at the moment <<esmtp>> does not honor mail aliases or
+ <<<.forward>>> files.
+
+ To deliver to other users beside yourself, the MDA must be installed with
+ <setuid> flag -- which is done by default in most Linux distributions.
+
+
+* Procmail
+~~~~~~~~~~
+
+ To use <<procmail>> with <<esmtp>> set the <<<mda>>> configuration value to:
+
+-----------------------------
+mda="/usr/bin/procmail -d %T"
+-----------------------------
+
+
+Interfacing with other mail applications
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+* Fetchmail
+~~~~~~~~~~~
+
+ By default <<fetchmail>> delivers messages via SMTP to port 25 on the machine
+ it is running. Because <<esmtp>> has no SMTP server if you are not using another
+ MTA for local delivery then you will need to configure <<fetchmail>> to use
+ <<esmtp>> executable. This is acomplished by adding the following lines to the top
+ of your <<<~/.fetchmailrc>>>:
+
+-------------------------------------
+defaults
+ mda "/path/to/esmtp -f %F %T"
+-------------------------------------
+
+ Since <<esmtp>> simply forwards the mail to another MDA you can avoid this
+ redundant step by simply replacing the value inside the quotes above by
+ whichever value you use on your <<<~/.esmtprc>>>.
-See ESMTP home page http://esmtp.sourceforge.net/ for more information.
diff --git a/TODO b/TODO
index 094a84d..130ec16 100644
--- a/TODO
+++ b/TODO
@@ -1 +1,13 @@
-- add a man page for the configuration file
+To do
+~~~~~
+
+ <<esmtp>> already fullfils all my needs, and I don't plan to spend more time
+ on it besides bug-fixing and some minor feature enhancements.
+
+ Here is a list of what can still be done:
+
+ * Add a man page for the configuration file.
+
+ * Alias expansion.
+
+
diff --git a/esmtp.1 b/esmtp.1
index f8f6a1c..6842853 100644
--- a/esmtp.1
+++ b/esmtp.1
@@ -49,7 +49,7 @@ Use sendmail.cf even if the operation mode indicates an initial mail
submission.
.TP
-\fB\-B\fR \fItype\fR (ignored)
+\fB\-B\fR \fItype\fR
Set the body type to \fItype\fR. Current legal values are 7BIT or 8BITMIME.
.TP
@@ -143,7 +143,7 @@ This should be set if you are reading data from a file.
Set the identifier used in syslog messages to the supplied \fItag\fR.
.TP
-\f\-N\fR \fIdsn\fR
+\fB\-N\fR \fIdsn\fR
Set delivery status notification conditions to \fIdsn\fR, which can be `never'
for no notifications or a comma separated list of the values `failure' to be
notified if delivery failed, `delay' to be notified if delivery is delayed, and
@@ -202,7 +202,7 @@ Limit processed jobs to those containing \fIsubstr\fR as a substring of the
sender or not when \fI!\fR is specified.
.TP
-\fB\-R\fR \fIreturn\fR (ignored)
+\fB\-R\fR \fIreturn\fR
Set the amount of the message to be returned if the message bounces. The
\fIreturn\fR parameter can be `full' to return the entire message or `hdrs' to
return only the headers. In the latter case also local bounces return only the
@@ -218,7 +218,7 @@ Read message for recipients. To:, Cc:, and Bcc: lines will be scanned for
recipient addresses. The Bcc: line will be deleted before transmission.
.TP
-\fB\-V\fR \fIenvid\fR (ignored)
+\fB\-V\fR \fIenvid\fR
Set the original envelope id.
.TP
diff --git a/local.c b/local.c
index a2545bf..29601d2 100644
--- a/local.c
+++ b/local.c
@@ -4,11 +4,11 @@
*/
+#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
-#include <pwd.h>
#include "local.h"
#include "main.h"
@@ -45,7 +45,6 @@ void local_init(message_t *message)
struct idlist *idp;
int length = 0, fromlen = 0, nameslen = 0;
char *names = NULL, *before, *after, *from = NULL;
- char *user = NULL;
if (!mda)
{
@@ -70,8 +69,9 @@ void local_init(message_t *message)
{
recipient_t *recipient = list_entry(ptr, recipient_t, list);
- if(recipient->address)
- nameslen += (strlen(recipient->address) + 1); /* string + ' ' */
+ assert(recipient->address);
+
+ nameslen += (strlen(recipient->address) + 1); /* string + ' ' */
}
names = (char *)xmalloc(nameslen + 1); /* account for '\0' */
@@ -80,13 +80,8 @@ void local_init(message_t *message)
{
recipient_t *recipient = list_entry(ptr, recipient_t, list);
- if(recipient->address)
- {
- if(!user)
- user = recipient->address;
- strcat(names, recipient->address);
- strcat(names, " ");
- }
+ strcat(names, recipient->address);
+ strcat(names, " ");
}
names[--nameslen] = '\0'; /* chop trailing space */
diff --git a/main.c b/main.c
index 8945533..54085f2 100644
--- a/main.c
+++ b/main.c
@@ -30,29 +30,50 @@ int verbose = 0;
FILE *log_fp = NULL;
+static void message_send(message_t *message)
+{
+ int local, remote;
+
+ local = !list_empty(&message->local_recipients);
+ remote = !list_empty(&message->remote_recipients);
+
+ if(remote && !local)
+ smtp_send(message);
+ else if(!remote && local)
+ {
+ local_init(message);
+ local_flush(message);
+ local_cleanup();
+ }
+ else
+ {
+ local_init(message);
+ smtp_send(message);
+ local_flush(message);
+ local_cleanup();
+ }
+}
+
int main (int argc, char **argv)
{
int c;
- enum notify_flags notify = Notify_NOTSET;
- char *from = NULL;
message_t *message;
- int parse_headers = 0, local, remote;
+ int parse_headers = 0;
opmode_t mode;
char *rcfile = NULL;
- identities_init();
+ message = message_new();
/* Set the default mode of operation. */
- if (strcmp(argv[0], "mailq") == 0) {
+ if (!strcmp(argv[0], "mailq")) {
mode = MAILQ;
- } else if (strcmp(argv[0], "newaliases") == 0) {
+ } else if (!strcmp(argv[0], "newaliases")) {
mode = NEWALIAS;
} else {
mode = ENQUEUE;
}
- while ((c = getopt (argc, argv,
- "A:B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtV:vX:")) != EOF)
+ while ((c = getopt (argc, argv, "A:B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtV:vX:")) != EOF)
switch (c)
{
case 'A':
@@ -61,6 +82,15 @@ int main (int argc, char **argv)
case 'B':
/* Body type */
+ if (!strcmp (optarg, "7BIT"))
+ message->body = E8bitmime_7BIT;
+ else if (!strcmp (optarg, "8BITMIME"))
+ message->body = E8bitmime_8BITMIME;
+ else
+ {
+ fprintf (stderr, "Unsupported body type %s\n", optarg);
+ exit (EX_USAGE);
+ }
break;
case 'C':
@@ -91,21 +121,25 @@ int main (int argc, char **argv)
case 'N':
/* Delivery status notifications */
- if (strcmp (optarg, "never") == 0)
- notify = Notify_NEVER;
+ if (!strcmp (optarg, "never"))
+ message->notify = Notify_NEVER;
else
{
if (strstr (optarg, "failure"))
- notify |= Notify_FAILURE;
+ message->notify |= Notify_FAILURE;
if (strstr (optarg, "delay"))
- notify |= Notify_DELAY;
+ message->notify |= Notify_DELAY;
if (strstr (optarg, "success"))
- notify |= Notify_SUCCESS;
+ message->notify |= Notify_SUCCESS;
}
break;
case 'R':
/* What to return */
+ if (!strcmp (optarg, "full"))
+ message->ret |= Ret_FULL;
+ if (!strcmp (optarg, "hdrs"))
+ message->ret |= Ret_HDRS;
break;
case 'T':
@@ -121,7 +155,7 @@ int main (int argc, char **argv)
case 'V':
/* Set original envelope id */
- break;
+ message_set_envid(message, optarg);
case 'b':
/* Operations mode */
@@ -190,7 +224,7 @@ int main (int argc, char **argv)
/* From address */
case 'r':
/* Obsolete -f flag */
- from = optarg;
+ message_set_reverse_path(message, optarg);
break;
case 'h':
@@ -265,6 +299,11 @@ int main (int argc, char **argv)
case 't':
/* Read recipients from message */
+ if(!message_parse_headers(message))
+ {
+ fprintf(stderr, "No recipients found\n");
+ exit(EX_DATAERR);
+ }
parse_headers = 1;
break;
@@ -287,7 +326,7 @@ int main (int argc, char **argv)
printf ("Mail queue is empty\n");
case NEWALIAS:
case FLUSHQ:
- exit (0);
+ goto done;
}
/* At least one more argument is needed. */
@@ -297,49 +336,21 @@ int main (int argc, char **argv)
exit (EX_USAGE);
}
- /* Parse the rc file. */
- rcfile_parse(rcfile);
-
- message = message_new();
-
- /** Parse the envelope headers */
- if(parse_headers)
- if(!message_parse_headers(message))
- {
- fprintf(stderr, "No recipients found\n");
- exit(EX_DATAERR);
- }
-
- /* Set the reverse path for the mail envelope. */
- if(from)
- message_set_reverse_path (message, from);
-
/* Add remaining program arguments as message recipients. */
while (optind < argc)
message_add_recipient(message, argv[optind++]);
- local = !list_empty(&message->local_recipients);
- remote = !list_empty(&message->remote_recipients);
-
- if(remote && !local)
- smtp_send(message);
- else if(!remote && local)
- {
- local_init(message);
- local_flush(message);
- local_cleanup();
- }
- else
- {
- local_init(message);
- smtp_send(message);
- local_flush(message);
- local_cleanup();
- }
-
- message_free(message);
+ identities_init();
+
+ /* Parse the rc file. */
+ rcfile_parse(rcfile);
+ message_send(message);
+
identities_cleanup();
+done:
+ message_free(message);
+
exit(EX_OK);
}
diff --git a/message.c b/message.c
index 8adb463..5f487d6 100644
--- a/message.c
+++ b/message.c
@@ -28,7 +28,9 @@ message_t *message_new(void)
INIT_LIST_HEAD(&message->remote_recipients);
INIT_LIST_HEAD(&message->local_recipients);
+ message->ret = Ret_NOTSET;
message->notify = Notify_NOTSET;
+ message->body = E8bitmime_NOTSET;
return message;
}
@@ -47,8 +49,9 @@ void message_free(message_t *message)
recipient = list_entry(ptr, recipient_t, list);
list_del(ptr);
- if(recipient->address)
- free(recipient->address);
+ assert(recipient->address);
+
+ free(recipient->address);
free(ptr);
}
@@ -59,12 +62,16 @@ void message_free(message_t *message)
recipient = list_entry(ptr, recipient_t, list);
list_del(ptr);
- if(recipient->address)
- free(recipient->address);
+ assert(recipient->address);
+
+ free(recipient->address);
free(ptr);
}
+ if(message->envid)
+ free(message->envid);
+
if(message->fp)
fclose(message->fp);
@@ -79,18 +86,29 @@ void message_set_reverse_path(message_t *message, const char *address)
message->reverse_path = xstrdup(address);
}
+void message_set_envid(message_t *message, const char *address)
+{
+ if(message->envid)
+ free(message->envid);
+
+ message->envid = xstrdup(address);
+}
+
void message_add_recipient(message_t *message, const char *address)
{
recipient_t *recipient;
- recipient = (recipient_t *)xmalloc(sizeof(recipient_t));
+ if(address)
+ {
+ recipient = (recipient_t *)xmalloc(sizeof(recipient_t));
- recipient->address = xstrdup(address);
+ recipient->address = xstrdup(address);
- if(local_address(address))
- list_add(&recipient->list, &message->local_recipients);
- else
- list_add(&recipient->list, &message->remote_recipients);
+ if(local_address(address))
+ list_add(&recipient->list, &message->local_recipients);
+ else
+ list_add(&recipient->list, &message->remote_recipients);
+ }
}
static void message_buffer_alloc(message_t *message)
@@ -305,8 +323,7 @@ static unsigned message_parse_header(message_t *message, size_t start, size_t st
unsigned message_parse_headers(message_t *message)
{
- FILE *fp = message->fp ? message->fp : stdin;
- char *line, *header;
+ char *line;
size_t start, stop;
unsigned count = 0;
diff --git a/message.h b/message.h
index 52aba01..a4c4b15 100644
--- a/message.h
+++ b/message.h
@@ -30,8 +30,16 @@ typedef struct {
struct list_head remote_recipients; /**< remote recipients */
struct list_head local_recipients; /**< local recipients */
- enum notify_flags notify; /**< libESMTP notificiation flags */
+ /** \name Delivery Status Notification (DSN) flags */
+ /*@{*/
+ enum ret_flags ret; /**< reporting options */
+ char *envid; /**< envelope identifier */
+ enum notify_flags notify; /**< notification options */
+ /*@}*/
+ /** 8bit-MIME transport */
+ enum e8bitmime_body body;
+
/** \name buffering */
/*@{*/
char *buffer;
@@ -53,6 +61,8 @@ void message_set_reverse_path(message_t *message, const char *address);
void message_add_recipient(message_t *message, const char *address);
+void message_set_envid(message_t *message, const char *address);
+
unsigned message_parse_headers(message_t *message);
size_t message_read(message_t *message, char *ptr, size_t size);
diff --git a/rfc822.c b/rfc822.c
index 0035ad2..546f481 100644
--- a/rfc822.c
+++ b/rfc822.c
@@ -37,9 +37,9 @@
*/
char *next_address(const char *hdr)
{
- static unsigned char address[BUFSIZ];
+ static char address[BUFSIZ];
static int tp;
- static const unsigned char *hp;
+ static const char *hp;
static int state, oldstate;
int parendepth = 0;
@@ -68,14 +68,14 @@ char *next_address(const char *hdr)
tp = 0;
return (address);
}
- return((unsigned char *)NULL);
+ return(NULL);
}
else if (*hp == '\\') /* handle RFC822 escaping */
{
if (state != INSIDE_PARENS)
{
address[NEXTTP()] = *hp++; /* take the escape */
- address[NEXTTP()] = *hp; /* take following unsigned char */
+ address[NEXTTP()] = *hp; /* take following char */
}
}
else switch (state)
diff --git a/sample.esmtprc b/sample.esmtprc
index 8ff89f0..f44db65 100644
--- a/sample.esmtprc
+++ b/sample.esmtprc
@@ -5,25 +5,10 @@
# Set SMTP host and service (port)
#
hostname = localhost:25
-#
-# This is specified in the format host.example.org[:service] with no whitespace
-# surrounding the colon if service is specified. service may be a name from
-# /etc/services or a decimal port number. If not specified the port defaults to
-# 587.
-#
-# NOTE (from libESMTP documentation): The default port number is set to 587
-# since this is the port that should be used for mail submission, see RFC 2476.
-# By choosing this default now, the API does not change behaviour unexpectedly
-# in the future as use of the new standard becomes commonplace. The hostport
-# nototion simplifies things for the application, the user can type
-# localhost:smtp or localhost:25 where the application expects a host name.
# Set the user name
#
username = "USERNAME"
-#
-# Note that the equal and quotes are optional but can be helpful in certain
-# circumstances.
# Set the password
password = "PASSWORD"
@@ -43,10 +28,10 @@ password = "PASSWORD"
# Same as above but for a different identity which can be selected with the
# '-f' flag. You can have as many you like.
#
-identity myself@somewhere.com
- hostname smtp.somewhere.com:25
- username "myself"
- password "secret"
+identity = myself@somewhere.com
+ hostname = smtp.somewhere.com:25
+ username = "myself"
+ password = "secret"
#starttls = disabled
#
# NOTE: the default indentity settings aren't shared by the other identities.
@@ -58,8 +43,5 @@ identity myself@somewhere.com
#
mda = "/usr/bin/procmail -d %T"
#
-# Some possible MDAs are
-# - "/usr/bin/procmail -d %T"
-# - "/usr/bin/deliver"
-# - "/usr/sbin/sendmail -i -f %F %T"
-# - "/usr/lib/mail.local %s"
+# Some possible MDAs are "/usr/bin/procmail -d %T", "/usr/bin/deliver" or
+# "/usr/lib/mail.local %T".
diff --git a/smtp.c b/smtp.c
index 3c3e4fa..033edaf 100644
--- a/smtp.c
+++ b/smtp.c
@@ -155,87 +155,101 @@ static const char * message_cb (void **buf, int *len, void *arg)
static void event_cb (smtp_session_t session, int event_no, void *arg, ...)
{
- FILE *fp = arg;
va_list ap;
const char *mailbox;
smtp_message_t message;
smtp_recipient_t recipient;
const smtp_status_t *status;
- static int sizeticking = 0, sizeticker;
-
- if (event_no != SMTP_EV_MESSAGEDATA && sizeticking)
- {
- fputs("\n", fp);
- sizeticking = 0;
- }
va_start (ap, arg);
+
switch (event_no) {
- case SMTP_EV_CONNECT:
- fputs("Connected to MTA\n", fp);
- break;
-
- case SMTP_EV_MAILSTATUS:
- mailbox = va_arg (ap, const char *);
- message = va_arg (ap, smtp_message_t);
- status = smtp_reverse_path_status (message);
- fprintf (fp, "From %s: %d %s", mailbox, status->code, status->text);
+ case SMTP_EV_EXTNA_DSN:
+ fprintf(stderr, "Delivery Status Notification extension not supported by MTA\n");
break;
-
- case SMTP_EV_RCPTSTATUS:
- mailbox = va_arg (ap, const char *);
- recipient = va_arg (ap, smtp_recipient_t);
- status = smtp_recipient_status (recipient);
- fprintf (fp, "To %s: %d %s", mailbox, status->code, status->text);
+ case SMTP_EV_EXTNA_8BITMIME:
+ fprintf(stderr, "8bit-MIME extension not supported by MTA\n");
break;
-
- case SMTP_EV_MESSAGEDATA:
- message = va_arg (ap, smtp_message_t);
- if (!sizeticking)
- {
- fputs("Message data: ", fp);
- sizeticking = 1;
- sizeticker = SIZETICKER - 1;
- }
- sizeticker += va_arg (ap, int);
- while (sizeticker >= SIZETICKER)
- {
- fputc('.', fp);
- sizeticker -= SIZETICKER;
- }
+ case SMTP_EV_EXTNA_STARTTLS:
+ fprintf(stderr, "StartTLS extension not supported by MTA\n");
break;
+ }
+
+ if (verbose)
+ {
+ static int sizeticking = 0, sizeticker;
- case SMTP_EV_MESSAGESENT:
- message = va_arg (ap, smtp_message_t);
- status = smtp_message_transfer_status (message);
- fprintf (fp, "Message sent: %d %s", status->code, status->text);
- break;
-
- case SMTP_EV_DISCONNECT:
- fputs("Disconnected to MTA\n", fp);
- break;
-
- default:
- break;
+ if (event_no != SMTP_EV_MESSAGEDATA && sizeticking)
+ {
+ fputs("\n", stdout);
+ sizeticking = 0;
+ }
+
+ switch (event_no) {
+ case SMTP_EV_CONNECT:
+ fputs("Connected to MTA\n", stdout);
+ break;
+
+ case SMTP_EV_MAILSTATUS:
+ mailbox = va_arg (ap, const char *);
+ message = va_arg (ap, smtp_message_t);
+ status = smtp_reverse_path_status (message);
+ fprintf (stdout, "From %s: %d %s", mailbox, status->code, status->text);
+ break;
+
+ case SMTP_EV_RCPTSTATUS:
+ mailbox = va_arg (ap, const char *);
+ recipient = va_arg (ap, smtp_recipient_t);
+ status = smtp_recipient_status (recipient);
+ fprintf (stdout, "To %s: %d %s", mailbox, status->code, status->text);
+ break;
+
+ case SMTP_EV_MESSAGEDATA:
+ message = va_arg (ap, smtp_message_t);
+ if (!sizeticking)
+ {
+ fputs("Message data: ", stdout);
+ sizeticking = 1;
+ sizeticker = SIZETICKER - 1;
+ }
+ sizeticker += va_arg (ap, int);
+ while (sizeticker >= SIZETICKER)
+ {
+ fputc('.', stdout);
+ sizeticker -= SIZETICKER;
+ }
+ break;
+
+ case SMTP_EV_MESSAGESENT:
+ message = va_arg (ap, smtp_message_t);
+ status = smtp_message_transfer_status (message);
+ fprintf (stdout, "Message sent: %d %s", status->code, status->text);
+ break;
+
+ case SMTP_EV_DISCONNECT:
+ fputs("Disconnected to MTA\n", stdout);
+ break;
+ }
}
+
va_end (ap);
}
static void monitor_cb (const char *buf, int buflen, int writing, void *arg)
{
- FILE *fp = arg;
+ assert(log_fp);
if (writing == SMTP_CB_HEADERS)
{
- fputs ("H: ", fp);
- fwrite (buf, 1, buflen, fp);
+ fputs ("H: ", log_fp);
+ fwrite (buf, 1, buflen, log_fp);
return;
}
- fputs (writing ? "C: " : "S: ", fp);
- fwrite (buf, 1, buflen, fp);
+ fputs (writing ? "C: " : "S: ", log_fp);
+ fwrite (buf, 1, buflen, log_fp);
if (buf[buflen - 1] != '\n')
- putc ('\n', fp);
+ putc ('\n', log_fp);
}
/**
@@ -306,7 +320,6 @@ void smtp_send(message_t *msg)
auth_context_t authctx;
const smtp_status_t *status;
struct sigaction sa;
- int ret;
identity_t *identity;
struct list_head *ptr;
@@ -314,19 +327,21 @@ void smtp_send(message_t *msg)
* session.
*/
auth_client_init ();
- session = smtp_create_session ();
+ if(!(session = smtp_create_session ()))
+ goto failure;
/* Add a protocol monitor. */
if(log_fp)
- smtp_set_monitorcb (session, monitor_cb, log_fp, 1);
+ if(!smtp_set_monitorcb (session, monitor_cb, NULL, 1))
+ goto failure;
/* Lookup the identity */
identity = identity_lookup(msg->reverse_path);
assert(identity);
/* Set the event callback. */
- if(verbose)
- smtp_set_eventcb (session, event_cb, stdout);
+ if(!smtp_set_eventcb (session, event_cb, NULL))
+ goto failure;
/* NB. libESMTP sets timeouts as it progresses through the protocol. In
* addition the remote server might close its socket on a timeout.
@@ -341,10 +356,12 @@ void smtp_send(message_t *msg)
* number of 587, however this is not widely deployed so the port is
* specified as 25 along with the default MTA host.
*/
- smtp_set_server (session, identity->host ? identity->host : "localhost:25");
+ if(!smtp_set_server (session, identity->host ? identity->host : "localhost:25"))
+ goto failure;
/* Set the SMTP Starttls extension. */
- smtp_starttls_enable (session, identity->starttls);
+ if(!smtp_starttls_enable (session, identity->starttls))
+ goto failure;
/* Do what's needed at application level to use authentication. */
authctx = auth_create_context ();
@@ -354,39 +371,57 @@ void smtp_send(message_t *msg)
/* Use our callback for X.509 certificate passwords. If STARTTLS is not in
* use or disabled in configure, the following is harmless.
*/
- smtp_starttls_set_password_cb (tlsinteract, identity);
+ if(!smtp_starttls_set_password_cb (tlsinteract, identity))
+ goto failure;
/* Now tell libESMTP it can use the SMTP AUTH extension. */
- smtp_auth_set_context (session, authctx);
+ if(!smtp_auth_set_context (session, authctx))
+ goto failure;
/* At present it can't handle one recipient only out of many failing. Make
* libESMTP require all specified recipients to succeed before transferring
* a message.
*/
- smtp_option_require_all_recipients (session, 1);
+ if(!smtp_option_require_all_recipients (session, 1))
+ goto failure;
/* Add a message to the SMTP session. */
- message = smtp_add_message (session);
+ if(!(message = smtp_add_message (session)))
+ goto failure;
/* Set the reverse path for the mail envelope. (NULL is ok) */
- smtp_set_reverse_path (message, msg->reverse_path);
+ if(!smtp_set_reverse_path (message, msg->reverse_path))
+ goto failure;
/* Open the message file and set the callback to read it. */
- smtp_set_messagecb (message, message_cb, msg);
+ if(!smtp_set_messagecb (message, message_cb, msg))
+ goto failure;
+
+ /* DSN options */
+ if(!smtp_dsn_set_ret(message, msg->ret))
+ goto failure;
+ if(msg->envid)
+ if(!smtp_dsn_set_envid(message, msg->envid))
+ goto failure;
+
+ /* 8bit-MIME */
+ if(!smtp_8bitmime_set_body(message, msg->body))
+ goto failure;
/* Add remaining program arguments as message recipients. */
list_for_each(ptr, &msg->remote_recipients)
{
recipient_t *entry = list_entry(ptr, recipient_t, list);
- if(entry->address)
- {
- recipient = smtp_add_recipient (message, entry->address);
-
- /* Recipient options set here */
- if (msg->notify != Notify_NOTSET)
- smtp_dsn_set_notify (recipient, msg->notify);
- }
+ assert(entry->address);
+
+ if(!(recipient = smtp_add_recipient (message, entry->address)))
+ goto failure;
+
+ /* Recipient options set here */
+ if (msg->notify != Notify_NOTSET)
+ if(!smtp_dsn_set_notify (recipient, msg->notify))
+ goto failure;
}
/* Initiate a connection to the SMTP server and transfer the message. */
@@ -397,23 +432,21 @@ void smtp_send(message_t *msg)
fprintf (stderr, "SMTP server problem %s\n",
smtp_strerror (smtp_errno (), buf, sizeof(buf)));
- ret = EX_UNAVAILABLE;
+ exit(EX_UNAVAILABLE);
}
- else
+
+
+ /* Report on the success or otherwise of the mail transfer. */
+ if(!(status = smtp_message_transfer_status (message)))
+ goto failure;
+ if (status->code / 100 != 2)
{
- /* Report on the success or otherwise of the mail transfer. */
+ /* Report on the failure of the mail transfer. */
status = smtp_message_transfer_status (message);
- if (status->code / 100 == 2)
- ret = EX_OK;
- else
- {
- /* Report on the failure of the mail transfer. */
- status = smtp_message_transfer_status (message);
- fprintf (stderr, "%d %s\n", status->code, status->text);
- smtp_enumerate_recipients (message, print_recipient_status, NULL);
+ fprintf (stderr, "%d %s\n", status->code, status->text);
+ smtp_enumerate_recipients (message, print_recipient_status, NULL);
- ret = EX_SOFTWARE;
- }
+ exit(EX_SOFTWARE);
}
if (log_fp)
@@ -423,8 +456,17 @@ void smtp_send(message_t *msg)
auth_destroy_context (authctx);
auth_client_exit ();
- if (ret != EX_OK)
- exit(ret);
+ return;
+
+failure:
+ {
+ char buf[128];
+
+ fprintf (stderr, "%s\n",
+ smtp_strerror (smtp_errno (), buf, sizeof(buf)));
+
+ exit(EX_SOFTWARE);
+ }
}
/*@}*/
diff --git a/smtp.h b/smtp.h
index 233c078..cc3fac8 100644
--- a/smtp.h
+++ b/smtp.h
@@ -22,12 +22,22 @@
*/
typedef struct {
struct list_head list;
- char *address;
- char *host;
+
+ char *address; /**< reverse path address */
+
+ char *host; /**< hostname and service (port) */
+
+ /** \name Auth Extension */
+ /*@{*/
char *user;
char *pass;
- enum starttls_option starttls; /**< it should default to Starttls_DISABLED */
+ /*@}*/
+
+ /** \name StartTLS Extension */
+ /*@{*/
+ enum starttls_option starttls;
char *certificate_passphrase;
+ /*@}*/
} identity_t;
/**