[comp.mail.sendmail] Keeping mail in the queue when mail cannot be delivered

bengsig@oracle.nl (Bjorn Engsig) (06/21/89)

In one of our sendmail.cf's, I use a specific mailer defined with a
Mmailer line.  There can be more reasons for this mailer not being able
to deliver the mail:

1. The address given to it is invalid, unknown, etc

2. The mailer is temporarily unable to deliver the mail, e.g. another
   machine is down, disconnected from the network etc.

What I would like to do, is to return the mail to sender in case 1, but
simply let the mail be in the sendmail queue in case 2 and let sendmail
try again on it's next queue run.  Currently, my mailer prints error
messages and returns non-zero in both cases, whereby sendmail returns the
whole thing to the sender.

How do I specify, that sendmail should keep the mail in the queue like it
does it with currently unreachble tcp machines.  I do not want to change
sendmail itself, but only the sendmail.cf and the mailer program.
Any good solutions, less good ones, kludges, etc. are very welcome.
-- 
Bjorn Engsig, ORACLE Europe         \ /    "Hofstadter's Law:  It always takes
Path:   mcvax!orcenl!bengsig         X      longer than you expect, even if you
Domain: bengsig@oracle.nl           / \     take into account Hofstadter's Law"

karl@giza.cis.ohio-state.edu (Karl Kleinpaste) (06/22/89)

To cause sendmail to re-queue a piece of mail, the Mmailer called
should exit(EX_TEMPFAIL).  From <sysexits.h>:

**      EX_TEMPFAIL -- temporary failure, indicating something that
**              is not really an error.  In sendmail, this means
**              that a mailer (e.g.) could not create a connection,
**              and the request should be reattempted later.

--Karl

jsloan@thor.wright.edu (John Sloan) (06/22/89)

From article <KARL.89Jun21171531@giza.cis.ohio-state.edu>, by karl@giza.cis.ohio-state.edu (Karl Kleinpaste):
> To cause sendmail to re-queue a piece of mail, the Mmailer called
> should exit(EX_TEMPFAIL).  From <sysexits.h>:
> A

For mailers which are too brain damaged to do this, like the
Ultrix/DECnet mail11, which takes the rather rude approach in emulating
VMS mail11 in that if it can't make a network connection immediately,
it throws away your email, you can wrap another program around your
mailer and then call the wrapper from Sendmail. e.g.


/*
**	D N E T M A I L
**
**	Module		dnetmail
**	Author		jsloan@CS.Wright.EDU
**	Project		DECnet/Ultrix
**	System		Ultrix-32
**	Date		18Jun1986
**	Modifications
**	
**		17Apr1987	jsloan		improved exit statuses
**		18Jun1987	jsloan		added more debugging stuff
**
**	Abstract
**
**		Frontend which sits betweem Sendmail and Mail11.
**		Rewrites user address(es), replacing '_' with '$'.
**		This is done because VMS allows $s in user names,
**		but Sendmail uses '$' internally. Hack hack hack.
**		Does not correct headers, so meaningful internet
**		routing is difficult. Does not handle multiple
**		users dues to laziness of author.
**
**		Now returns more meaningful statuses to Sendmail than
**		possible with Mail11.
**
**		Dnetmail will keep a trace of messages for debugging
**		purposes in the file /tmp/DECnetTrace provided the
**		file already exists. This feature is compiled in only
**		if DEBUG is defined.
**
**		Compile with something similar to
**
**			cc -O -o dnetmail dnetmail.c
**			strip dnetmail
**			cp dnetmail /usr/local/mail
**
**		Called from Sendmail as
**
**			dnetmail from name to user < message
**
*/

static char header[]="@(#) dnetmail.c version 1.2 from 88/01/27 by jsloan@SPOTS.Wright.Edu";

#include <stdio.h>
#include <ctype.h>
#include <sysexits.h>

#define TRACE "/tmp/DECnetTrace"
#define MAIL11 "/usr/bin/mail11 \'%s\' \'%s\' \'%s\' \'%s\'" 
#define OLD '_'
#define NEW '$'

extern char *malloc(), *strcopy(), *strcat();
extern int strlen();
extern FILE *popen();
extern int pclose();

main(argc,argv)
int argc;
char **argv;
	{
	char *from, *name, *to, *user, command[512], work[512];
	FILE *trace, *pipefd;
	int index, status;

#ifdef DEBUG
	if ((trace=fopen(TRACE,"r"))!=NULL)
		{
		fclose(trace);
		trace = fopen(TRACE,"a");
		}
#endif
	if (argc != 5)
		{
		fprintf(stderr,"dnetmail: %d arguments, exit %d\n",argc,EX_USAGE);
		exit(EX_USAGE);
		}
	from = argv[1];
	name = argv[2];
	to = argv[3];
	user = argv[4];
	for (index = 0; index <= strlen(user); index++)
		if (user[index] == OLD)
			user[index] = NEW;
	sprintf(command,MAIL11,from,name,to,user);
#ifdef DEBUG
	if (trace != NULL)
		fprintf(trace,"DNETMAIL exec \"%s\"\n",command);
#endif
	pipefd = popen(command,"w");
	if (pipefd == NULL)
		{
		fprintf(stderr,"dnetmail: popen failed, exit %d\n",EX_OSERR);
		exit(EX_OSERR);
		}
	while (fgets(work,sizeof(work),stdin))
		{
		fputs(work,pipefd);
#ifdef DEBUG
		if (trace != NULL)
			fputs(work,trace);
#endif
		}
	if ((status = pclose(pipefd)) != 0)
		{
		fprintf(stderr,"dnetmail: mail11 status %d, exit %d\n",status,EX_TEMPFAIL);
 		fprintf(stderr,"dnetmail: \"%s\" \"%s\" \"%s\" \"%s\"\n",from,name,to,user);
		exit(EX_TEMPFAIL);
		}
	exit(EX_OK);
	}

----------

Since the wrapper can't discriminate between unreachable hosts and
non-existent users (because the mailer just says "it didn't work"), it
will cause sendmail to reattempt delivery until the timeout period
specified in the cf is reached.

Maybe that's not so bad... if a user is finally defined on the target
system prior to expiration of the timeout, deliverly will eventually be
successful.

Man page available upon request.

John Sloan  +1 513 259 1384         jsloan%spots.wright.edu@relay.cs.net
Wright State University Research Center   ...!uunet!ncrlnk!wright!jsloan
3171 Research Blvd., Kettering, OH 45420       ...!osu-cis!wright!jsloan
Logical Disclaimer: belong(opinions,jsloan). belong(opinions,_):-!,fail.

avolio@decuac.dec.com (Frederick M. Avolio) (06/23/89)

It seems that John Sloanis running very old (version 1.0?) mail11 code.
It has worked correctly since the very next version.  In other words, 
the DECNET ULTRIX Mail11 mailer correctly bounces orleaves queued, 
depending on the error.

In fact, thinking about it, it NEVER bounced mail on HOST UNREACHABLE.
In the first version it did bounce mail oon such things as when the user's
mailbox was not reachable (unmounted file system for example).

Fred

pat@orac.pgh.pa.us (Pat Barron) (06/23/89)

In article <449.nlhp3@oracle.nl> bengsig@oracle.nl (Bjorn Engsig) writes:
>How do I specify, that sendmail should keep the mail in the queue like it
>does it with currently unreachble tcp machines.  I do not want to change
>sendmail itself, but only the sendmail.cf and the mailer program.
>Any good solutions, less good ones, kludges, etc. are very welcome.

Sendmail interprets exit codes from programs according to sysexits.h.
If you've written your own mailer, it should either exit with a zero
return code, or with one of the codes defined in sysexits.h.

If you look in sysexits.h, you will see that there is a return code
EX_TEMPFAIL defined to be use for temporary failures.  If your mailer
program calls "exit(EX_TEMPFAIL)" when it detects a temporary failure,
the mail should be retried.

--Pat.
-- 
Pat Barron
Internet:  pat@orac.pgh.pa.us  - or -   orac!pat@gateway.sei.cmu.edu
UUCP:  ...!uunet!apexepa!sei!orac!pat  - or -  ...!pitt!darth!orac!pat

bengsig@oracle.nl (Bjorn Engsig) (06/23/89)

From article <449.nlhp3@oracle.nl> by me:
|How do I specify, that sendmail should keep the mail in the queue like it
|does it with currently unreachble tcp machines.
Thank you; many replies suggest that the mailer (started from the Mmailer
line) should return one of the values from /usr/include/sysexit.h.  However,
a single person has actually looked into the code, and she claims that
only the [IPC] mail can be kept in queue.  It seems I'll have to do
some experimenting.
-- 
Bjorn Engsig, ORACLE Europe         \ /    "Hofstadter's Law:  It always takes
Path:   mcvax!orcenl!bengsig         X      longer than you expect, even if you
Domain: bengsig@oracle.nl           / \     take into account Hofstadter's Law"