Sendmail support for Cyrus IMAP IGNOREQUOTA LMTP extension

Cyrus IMAP system supports IGNOREQUOTA LMTP extension but Sendmail does not. What is the purpose of this extension and can we modify Sendmail to support it?


The relevant RFC can be found at:

LMTP Service Extension for Ignoring Recipient Quotas

The introduction states the rationale (emphasis by Kalevi Kolttonen):

In many cases, the [LMTP] protocol is used to transfer messages to a delivery agent which might impose some limits on the usage of system resources by individual recipients (e.g. disk space on a mailstore). Sometimes it may be desirable for an LMTP client to inject a message into the mailstore regardless of these quotas (e.g. an automated process notifying users that they are over quota).

The plan

So we need a way to tell Sendmail to use IGNOREQUOTA extension. I chose Sendmail 8.15.2 because as of this writing (Oct 14th, 2016), it is the latest version. I think it is the best solution to invent a new mailer flag that forces Sendmail to use IGNOREQUOTA. There is no need to construct a more complicated logic that would interpret the LHLO response from the server: We are doing local mail delivery after all and we already know in advance whether our LMTP server supports the IGNOREQUOTA extension or not.

The patch

Fortunately, and perhaps surprisingly, it turns out that the modifications to the Sendmail 8.15.2 source tree are very simple indeed. We only need to alter two files: sendmail/sendmail.h and sendmail/usersmtp.c. There is a total of 57 M_XXXXXXXX mailer flag #define definitions in sendmail.h, but two of them ('+' and '-') are characters that are reserved just for the Sendmail M4 macro configuration facility. What did I do?

  1. I chose an unused letter 'Q' to be the new mailer flag that forces Sendmail to use the IGNOREQUOTA extension
  2. I added one if-clause to check whether the 'Q' flag is set and to verify that there is enough space in the RCPT TO option buffer

You can download the gzipped Sendmail 8.15.2 patch from here.

The patch content looks like this:

diff -urp sendmail-8.15.2/sendmail/sendmail.h sendmail-8.15.2-patched/sendmail/sendmail.h
--- sendmail-8.15.2/sendmail/sendmail.h	2015-06-19 15:59:29.000000000 +0300
+++ sendmail-8.15.2-patched/sendmail/sendmail.h	2016-10-14 13:51:58.083469892 +0300
@@ -513,6 +513,7 @@ struct mailer
 #define M_PLUS		'+'	/* Reserved: Used in mc for adding new flags */
 #define M_MINUS		'-'	/* Reserved: Used in mc for removing flags */
 #define M_NOMHHACK	'!'	/* Don't perform HM hack dropping explicit from */
+#define M_IGNQUOTA	'Q'	/* Force IGNOREQUOTA RCPT TO LMTP extension */
 /* functions */
 extern void	initerrmailers __P((void));
diff -urp sendmail-8.15.2/sendmail/usersmtp.c sendmail-8.15.2-patched/sendmail/usersmtp.c
--- sendmail-8.15.2/sendmail/usersmtp.c	2014-12-05 17:42:28.000000000 +0200
+++ sendmail-8.15.2-patched/sendmail/usersmtp.c	2016-10-14 13:51:44.099380746 +0300
@@ -2376,6 +2376,15 @@ smtprcpt(to, m, mci, e, ctladdr, xstart)
+	/* Force IGNOREQUOTA RCPT TO LMTP extension? */
+	if (bitnset(M_IGNQUOTA, m->m_flags) &&
+	    SPACELEFT(optbuf, bufp) > 12)
+	{
+		(void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
+		bufp += strlen(bufp);
+	}
 	smtpmessage("RCPT To:<%s>%s", m, mci, to->q_user, optbuf);
 	mci->mci_state = MCIS_RCPT;

Sendmail configuration

I assume your LMTP server is Cyrus lmtpd that supports IGNOREQUOTA. We must next modify Sendmail's Cyrus V2 mailer definition to include our new 'Q' flag. Make sure your contains something like the following:

define(`CYRUSV2_MAILER_ARGS', `TCP $h 24')dnl

The corresponding mailer definition should then look like following, with the upper case 'Q' appended to the F= flags definition:

Mcyrusv2,	P=[IPC], F=lsDFMnqXzA@/:|mQ,
		S=EnvFromSMTP/HdrFromL, R=EnvToL/HdrToL, E=\r\n,
		A=TCP $h 24


Finally we should go through some notes about using the IGNOREQUOTA patched Sendmail. The simplicity comes with a price: Once you set the 'Q' mailer flag, every LMTP delivery succeeds provided that the recipient is valid and the LMTP server has not run out of disk space. That is why you should keep your regular Cyrus V2 Sendmail instance running in order to get the normal "over quota" responses, i.e. do not install the patched Sendmail binary as /usr/sbin/sendmail. Instead, you could put it elsewhere and when you need the IGNOREQUOTA patched Sendmail for sending out messages, you would just run it as client like this:

/path/to/patched/sendmail -Am -v -t < /path/to/your/message

Note that the IGNOREQUOTA patched Sendmail and the regular Sendmail could co-exist and even share the same configuration /etc/mail/ However, that might get confusing. The patched Sendmail would interpret the new 'Q' mailer flag, but the regular Sendmail would simply ignore it and run the cyrusv2 mailer in the standard way. Using the same could also lead to problems when the patched Sendmail could not deliver the message at the first try. Whatever reason for the initial failure, the message would end up in /var/spool/mqueue for later retries. The later retries would be done by the regular Sendmail, ignoring the 'Q' flag and failing due to over quota recipient boxes. When running two Sendmail instances on one host, they should have different configuration files and different mail queues to keep things working correctly.

Alternatively, you could just run the patched Sendmail on a special purpose host that is designed for sending out notifications even to those users whose quota has been exceeded. That way you would avoid the horrible hassle of managing two Sendmail instances on one host. This is definitely the option I would recommend.

Of course you could install the patched Sendmail as /usr/sbin/sendmail and control the LMTP IGNOREQUOTA behaviour by adding and removing the 'Q' mailer flag as needed. For example, you could leave it out for normal everyday use and enable it when in need of sending out important nofitications that should reach everyone no matter what.

Best regards,
Kalevi Kolttonen <>