Sendma...ontext(3pm)
π LICENSE π
Copyright (c) 2016-2026 G.W. Haywood. All rights reserved.
And like, massive thanks to everyone who trodden these paths before us π₯Ή, including Copyright (c) 2002-2004 Todd Vierling. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notices, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notices, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
- Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. In the case of G.W. Haywood this permission is hereby now granted.
okay bestie, now the part everyone scrolls past but which is literally the whole point β the ALL-CAPS scream, verbatim, no edits, because legal text is not a vibe you get to remix π:
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
β¨ NAME β¨
Sendmail::PMilter::Context β per-connection milter context π¦
(This whole page is the manual for Sendmail::PMilter::Context, aka <italic>Sendma...ontext</italic>(3pm), and yes it has a 3pm section because it is, in fact, a Perl module. iykyk π«Ά)
πΈ DESCRIPTION πΈ
okay so here's the tea β β a Sendmail::PMilter::Context is the context object that gets passed to your milter callback functions as the first argument. That's its whole job. It's the little bag of per-connection state that shows up at the top of every callback you write. π
People typically name it $ctx because, like, typing out Sendmail::PMilter::Context every single time? in this economy? no ma'am. $ctx is short, it's cute, it's giving convenience π
.
This document is here to walk you through every publicly accessible operation on this object β like, the stuff you're actually allowed to touch, no forbidden vibes, no reaching into the internals and poking at things that aren't yours π. If it's in here, it's public API. If it's not, hands off. periodt. β
π METHODS π
okay bestie, this is the good part β all the actual methods you'll be calling on your $ctx object. buckle up π
π $ctx->getpriv
hands you back the private data object for this milter instance β the one you stashed with $ctx->setpriv() (scroll down, it's right there). and if this milter instance has literally never called setpriv, you get undef. no data, no vibe, just undef. π«Ά
π $ctx->getsymval(NAME)
quick vocab moment before we go any further: when sendmail people say macro, they mean named variables that are basically just text strings. the MTA can define them, they get filled in as messages are processed, milters can define them, and the MTA's config files can define them too. iykyk. β¨
so getsymval grabs the macro symbol called NAME out of the macros the MTA has available for the current callback. NAME is either a one-character macro name, or a multi-character name wrapped in {curly braces}. if that macro is undefined at the moment you call getsymval, boom β you get undef back.
here are some common ones. the milter protocol was first implemented in the Sendmail MTA, so these macro names are the ones Sendmail itself uses; other MTAs, e.g. Postfix, may provide similar macros. π
$ctx->getsymval('_')β the remote host name and address, in standard SMTPname [address]form.$ctx->getsymval('i')β the MTA's queue ID for the current message.$ctx->getsymval('j')β the MTA's idea of the local host name.$ctx->getsymval('{if_addr}')β the local address of the network interface that the connection came in on.$ctx->getsymval('{if_name}')β the local hostname of the network interface that the connection came in on.$ctx->getsymval('{mail_addr}')β theMAIL FROM:sender's address, canonicalized and angle brackets stripped. (this is typically not the same value as the second argument to theenvfromcallback.) it'll be defined as the empty string''if the client issued aMAIL FROM:<>null return path command.$ctx->getsymval('{rcpt_addr}')β theRCPT TO:recipient's address, canonicalized and angle brackets stripped. (again, typically not the same as the second argument to theenvrcptcallback.)
β οΈ not every macro is available at every moment, bestie. some only show up after a specific phase is reached, and some only exist on certain MTA implementations. always check the returned values forundef. this version of theSendmail::PMilterpackage collects macro values only for these callbacks:CONNECT HELO ENVFROM ENVRCPT DATA EOH EOM
π $ctx->setpriv(DATA)
this is the spot to stash milter-private data that's tied to the current SMTP client connection. you can only store one value, so the usual move is to init an arrayref or hashref in the connect callback and set it with $ctx->setpriv. π§
then on later callback runs you can grab it back with $ctx->getpriv. cute, right?
π $ctx->setreply(RCODE, XCODE, MESSAGE)
set an extended SMTP status reply β you do this right before returning SMFIS_REJECT or SMFIS_TEMPFAIL. π
RCODEshould be a short (4xxor5xx) numeric reply code.XCODEshould be a long (4.x.yor5.x.y) ESMTP reply code.- the first digit of
RCODEmust be the same as the first digit ofXCODE. no such restriction on the other digits, go wild. - in
RCODEandXCODE,xshould be one decimal digit; inXCODE,yshould be either one or two decimal digits. MESSAGEis the full text of the message to send.
for the actual codes and suggested messages, go read the appropriate RFCs. examples:
$ctx->setreply(451, '4.7.0', 'Cannot authenticate you right now');
return SMFIS_TEMPFAIL;
$ctx->setreply(550, '5.7.26', 'Multiple authentication failures');
return SMFIS_REJECT;
π real talk: once you've set a reply with this method, the SMTP result code comes fromRCODE, not from the symbolic constantsSMFIS_REJECTandSMFIS_TEMPFAIL. but for consistency's sake, callbacks that set a4xxresponse code should still useSMFIS_TEMPFAIL, and the ones setting a5xxcode should returnSMFIS_REJECT.
returns 1 on success, undef on failure. on failure β which is typically only caused by bad parameters β a generic message gets sent based on the SMFIS_* return code.
π $ctx->setmlreply(RCODE, XCODE, MESSAGES)
same energy as above, also set before returning SMFIS_REJECT or SMFIS_TEMPFAIL. peek at setreply() above for the whole scoop on the reply codes RCODE and XCODE. π
MESSAGES is an array holding a multi-line reply. rules of the house:
- it must contain no less than two string elements.
- Sendmail dictates it must contain no more than 32 elements.
- each string element must hold no more than 980 characters (any of the strings may be NULL).
- no string may contain a newline (
"\n") or a carriage return ("\r") character. π«
example:
$ctx->setmlreply(451, '4.7.0', \('Cannot authenticate sender.',
'Please refer to our published policies at',
'http://www.example.com/policies')
);
return SMFIS_TEMPFAIL;
π again: after you set a reply with this, the SMTP result code comes fromRCODE, not fromSMFIS_REJECT/SMFIS_TEMPFAIL. but consistency!!4xxβ returnSMFIS_TEMPFAIL,5xxβ returnSMFIS_REJECT.
returns 1 on success, undef on failure. on failure β which is typically caused by bad parameters β a generic message gets sent based on the SMFIS_* return code.
π $ctx->shutdown()
this is a special case of $ctx->setreply() β it sets the short numeric reply code to 421 and the ESMTP code to 4.7.0. on Sendmail 8.13 and higher (and honestly you should not be running any version of Sendmail older than that), this closes the MTA's communication channel fast, which should immediately trigger a close callback and end milter execution. bye bestie π
returns 1.
π $ctx->addheader(HEADER, VALUE)
adds header HEADER with value VALUE to this mail. it does not change any existing headers with the same name. only callable from the eom callback. π
returns 1 on success, undef on failure.
π $ctx->insheader(HEADER, VALUE, POSITION)
inserts header HEADER at position POSITION with value VALUE into this mail. doesn't touch any existing headers with the same name. only callable from the eom callback.
HEADER and VALUE are required, but POSITION is optional. a POSITION of zero is totally acceptable and is the default when you don't pass one β that inserts HEADER before all existing headers. β
returns 1 on success, undef on failure.
π $ctx->chgheader(HEADER, INDEX, VALUE)
change the INDEX'th header named HEADER to the value VALUE. only callable from the eom callback. and if INDEX goes past the number of existing headers with that name, it just adds another header of that name. slay.
returns 1 on success, undef on failure.
π $ctx->addrcpt(ADDRESS)
add address ADDRESS to the recipient list for this mail. only callable from the eom callback. π¦
returns 1 on success, undef on failure.
π $ctx->addrcpt_par(ADDRESS,PARAMS)
add an address ADDRESS and its ESMTP arguments PARAMS to the recipient list for this mail. only callable from the eom callback.
returns 1 on success, undef on failure.
π $ctx->delrcpt(ADDRESS)
remove address ADDRESS from the recipient list for this mail. heads up: the ADDRESS argument has to match a previous argument to the envrcpt callback exactly β case sensitive, and including angle brackets if they were there. only callable from the eom callback. π₯
returns 1 on success, undef on failure. and a success return just means the command got queued for processing. it does not necessarily mean the recipient was successfully removed β that info isn't available from Sendmail. so don't @ me.
π $ctx->progress()
sends an asynchronous "progress" message to the MTA, so you can do longer-than-normal operations like extensive message body scanning or a deliberate delay. this command should only be issued during the EOM callback β call it any other time and it fails and returns undef. π
returns 1 if the call happens during EOM and is permitted, otherwise undef.
π $ctx->quarantine(REASON)
quarantine the current message in the MTA-defined quarantine area, using REASON as the text string describing the quarantine status. only callable from the eom callback. π
returns 1 on success, undef on failure.
π this method is an extension β it is not available in the standard Sendmail::Milter package.
π $ctx->replacebody(BUFFER)
replace the message body with the data in BUFFER (a scalar). you can call this multiple times, and each call appends to the replacement buffer. end-of-line should be represented by CR-LF ("\r\n"). only callable from the eom callback. β¨
returns 1 on success, undef on failure.
π $ctx->chgfrom(ADDRESS) =item $ctx->setsender(ADDRESS) (Deprecated)
replace the envelope sender address for the given mail message. β οΈ this one is deprecated, bestie.
returns 1 on success, undef on failure. and a successful return just means the command got queued for processing β it does not necessarily mean the operation actually completed, because that information is not available from Sendmail.
π SEE ALSO π
Sendmail::PMilterβ go read that one too, fr fr π
and that's the whole page, bestie!! π this was generated from perl v5.40.1 and dated 2026-07-05 β go forth and filter those milters, you absolute icon ππ
π¦
π¦ where this page comes from
- ubuntu stonking: libsendmail-pmilter-perl 1.28-1 Β· BSD-3-Clause
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms