pymilter  1.0.5
Public Member Functions | Public Attributes | Private Member Functions | Private Attributes | List of all members
Milter.Base Class Reference

A do "nothing" Milter base class representing an SMTP connection. More...

Inheritance diagram for Milter.Base:
Milter.Milter

Public Member Functions

def log (self, *msg)
 Defined by subclasses to write log messages.
 
def connect (self, hostname, family, hostaddr)
 Called for each connection to the MTA. More...
 
def hello (self, hostname)
 Called when the SMTP client says HELO. More...
 
def envfrom_bytes (self, *b)
 Called with bytes by default global envfrom callback. More...
 
def envfrom (self, f, *s)
 Called when the SMTP client says MAIL FROM. More...
 
def envrcpt_bytes (self, *b)
 Called with bytes by default global envrcpt callback. More...
 
def envrcpt (self, to, *str)
 Called when the SMTP client says RCPT TO. More...
 
def data (self)
 Called when the SMTP client says DATA. More...
 
def header_bytes (self, fld, val)
 Called with bytes by default global header callback. More...
 
def header (self, field, value)
 Called for each header field in the message body. More...
 
def eoh (self)
 Called at the blank line that terminates the header fields.
 
def body (self, blk)
 Called to supply the body of the message to the Milter by chunks. More...
 
def unknown (self, cmd)
 Called when the SMTP client issues an unknown command. More...
 
def eom (self)
 Called at the end of the message body. More...
 
def abort (self)
 Called when the connection is abnormally terminated. More...
 
def close (self)
 Called when the connection is closed.
 
def protocol_mask (klass)
 Return mask of SMFIP_N* protocol option bits to clear for this class The @nocallback and @noreply decorators set the milter_protocol function attribute to the protocol mask bit to pass to libmilter, causing that callback or its reply to be skipped. More...
 
def negotiate (self, opts)
 Negotiate milter protocol options. More...
 
def getsymval (self, sym)
 Return the value of an MTA macro. More...
 
def setreply (self, rcode, xcode=None, msg=None, *ml)
 Set the SMTP reply code and message. More...
 
def setsymlist (self, stage, *macros)
 Tell the MTA which macro names will be used. More...
 
def addheader (self, field, value, idx=-1)
 Add a mail header field. More...
 
def chgheader (self, field, idx, value)
 Change the value of a mail header field. More...
 
def addrcpt (self, rcpt, params=None)
 Add a recipient to the message. More...
 
def delrcpt (self, rcpt)
 Delete a recipient from the message. More...
 
def replacebody (self, body)
 Replace the message body. More...
 
def chgfrom (self, sender, params=None)
 Change the SMTP envelope sender address. More...
 
def quarantine (self, reason)
 Quarantine the message. More...
 
def progress (self)
 Tell the MTA to wait a bit longer. More...
 

Public Attributes

 header_bytes
 

Private Member Functions

def _setctx (self, ctx)
 Attach this Milter to the low level milter.milterContext object.
 

Private Attributes

 _ctx
 The low level milter.milterContext object.
 
 _actions
 A bitmask of actions this connection has negotiated to use. More...
 
 _protocol
 A bitmask of protocol options this connection has negotiated. More...
 

Detailed Description

A do "nothing" Milter base class representing an SMTP connection.

Python milters should derive from this class unless they are using the low level milter module directly.

Most of the methods are either "actions" or "callbacks". Callbacks are invoked by the MTA at certain points in the SMTP protocol. For instance when the HELO command is seen, the MTA calls the helo callback before returning a response code. All callbacks must return one of these constants: CONTINUE, TEMPFAIL, REJECT, ACCEPT, DISCARD, SKIP. The NOREPLY response is supplied automatically by the @noreply decorator if negotiation with the MTA is successful. @noreply and @nocallback methods should return CONTINUE for two reasons: the MTA may not support negotiation, and the class may be running in a test harness.

Optional callbacks are disabled with the @nocallback decorator, and automatically reenabled when overridden. Disabled callbacks should still return CONTINUE for testing and MTAs that do not support negotiation.

Member Function Documentation

◆ abort()

def Milter.Base.abort (   self)

Called when the connection is abnormally terminated.

The close callback is still called also.

Reimplemented in Milter.Milter.

◆ addheader()

def Milter.Base.addheader (   self,
  field,
  value,
  idx = -1 
)

Add a mail header field.

Calls smfi_addheader.
The Milter.ADDHDRS action flag must be set.

May be called from eom callback only.

Parameters
fieldthe header field name
valuethe header field value
idxheader field index from the top of the message to insert at
Exceptions
DisabledActionif ADDHDRS is not enabled

References Milter.Base._actions, and Milter.Base._ctx.

◆ addrcpt()

def Milter.Base.addrcpt (   self,
  rcpt,
  params = None 
)

Add a recipient to the message.


Calls smfi_addrcpt.
If no corresponding mail header is added, this is like a Bcc. The syntax of the recipient is the same as used in the SMTP RCPT TO command (and as delivered to the envrcpt callback), for example "self.addrcpt('<foo@example.com>')".
The Milter.ADDRCPT action flag must be set. If the optional params argument is used, then the Milter.ADDRCPT_PAR action flag must be set.

May be called from eom callback only.

Parameters
rcptthe message recipient
paramsan optional list of ESMTP parameters
Exceptions
DisabledActionif ADDRCPT or ADDRCPT_PAR is not enabled

References Milter.Base._actions, and Milter.Base._ctx.

◆ body()

def Milter.Base.body (   self,
  blk 
)

Called to supply the body of the message to the Milter by chunks.

Parameters
blka block of message bytes

Referenced by Milter.test.TestBase.feedFile().

◆ chgfrom()

def Milter.Base.chgfrom (   self,
  sender,
  params = None 
)

Change the SMTP envelope sender address.

Calls smfi_chgfrom.
The syntax of the sender is that same as used in the SMTP MAIL FROM command (and as delivered to the envfrom callback), for example self.chgfrom('bar@e.nosp@m.xamp.nosp@m.le.co.nosp@m.m'). The Milter.CHGFROM action flag must be set.

May be called from eom callback only.

Since
0.9.1
Parameters
senderthe new sender address
paramsan optional list of ESMTP parameters
Exceptions
DisabledActionif CHGFROM is not enabled

References Milter.Base._actions, and Milter.Base._ctx.

◆ chgheader()

def Milter.Base.chgheader (   self,
  field,
  idx,
  value 
)

Change the value of a mail header field.

Calls smfi_chgheader.
The Milter.CHGHDRS action flag must be set.

May be called from eom callback only.

Parameters
fieldthe name of the field to change
idxindex of the field to change when there are multiple instances
valuethe new value of the field
Exceptions
DisabledActionif CHGHDRS is not enabled

References Milter.Base._actions, and Milter.Base._ctx.

◆ connect()

def Milter.Base.connect (   self,
  hostname,
  family,
  hostaddr 
)

Called for each connection to the MTA.

Called by the xxfi_connect callback.
The hostname provided by the local MTA is either the PTR name or the IP in the form "[1.2.3.4]" if no PTR is available. The format of hostaddr depends on the socket family:

socket.AF_INET
A tuple of (IP as string in dotted quad form, integer port)
socket.AF_INET6
A tuple of (IP as a string in standard representation, integer port, integer flow info, integer scope id)
socket.AF_UNIX
A string with the socketname

To vary behavior based on what port the client connected to, for example skipping blacklist checks for port 587 (which must be authenticated), use getsymval('{daemon_port}') . The {daemon_port} macro must be enabled in sendmail.cf

 O Milter.macros.connect=j, _, {daemon_name}, {daemon_port}, {if_name}, {if_addr}
 

or sendmail.mc

 define(`confMILTER_MACROS_CONNECT', ``j, _, {daemon_name}, {daemon_port}, {if_name}, {if_addr}'')dnl
 
Parameters
hostnamethe PTR name or bracketed IP of the SMTP client
familysocket.AF_INET, socket.AF_INET6, or socket.AF_UNIX
hostaddra tuple or string with peer IP or socketname

Reimplemented in Milter.Milter.

◆ data()

def Milter.Base.data (   self)

Called when the SMTP client says DATA.

Returning REJECT rejects the message without wasting bandwidth on the unwanted message.

Since
0.9.2

Referenced by Milter.test.TestBase.feedFile().

◆ delrcpt()

def Milter.Base.delrcpt (   self,
  rcpt 
)

Delete a recipient from the message.

Calls smfi_delrcpt.
The recipient should match one passed to the envrcpt callback. The Milter.DELRCPT action flag must be set.

May be called from eom callback only.

Parameters
rcptthe message recipient to delete
Exceptions
DisabledActionif DELRCPT is not enabled

References Milter.Base._actions, and Milter.Base._ctx.

◆ envfrom()

def Milter.Base.envfrom (   self,
  f,
s 
)

Called when the SMTP client says MAIL FROM.

Called by the xxfi_envfrom callback.
Returning REJECT rejects the message, but not the connection. The sender is the "envelope" from as defined by RFC 5321. For the From: header (author) defined in RFC 5322, see the header callback .

Reimplemented in Milter.Milter.

Referenced by Milter.Base.envfrom_bytes(), and Milter.test.TestBase.feedFile().

◆ envfrom_bytes()

def Milter.Base.envfrom_bytes (   self,
b 
)

Called with bytes by default global envfrom callback.

Since
1.0.5 Converts from utf-8 to unicode with surrogate escape. Can be overriden to pass bytes to the header callback instead, or trap utf-8 conversion exception, etc.

References Milter.Base.envfrom(), and Milter.Milter.envfrom().

◆ envrcpt()

def Milter.Base.envrcpt (   self,
  to,
str 
)

Called when the SMTP client says RCPT TO.

Called by the xxfi_envrcpt callback. Returning REJECT rejects the current recipient, not the entire message. The recipient is the "envelope" recipient as defined by RFC 5321. For recipients defined in RFC 5322, for example To: or Cc:, see the header callback .

Reimplemented in Milter.Milter.

Referenced by Milter.Base.envrcpt_bytes(), and Milter.test.TestBase.feedFile().

◆ envrcpt_bytes()

def Milter.Base.envrcpt_bytes (   self,
b 
)

Called with bytes by default global envrcpt callback.

Since
1.0.5 Converts from utf-8 to unicode with surrogate escape. Can be overriden to pass bytes to the header callback instead, or trap utf-8 conversion exception, etc.

References Milter.Base.envrcpt(), and Milter.Milter.envrcpt().

◆ eom()

def Milter.Base.eom (   self)

Called at the end of the message body.

Most of the message manipulation actions can only take place from the eom callback.

Reimplemented in Milter.Milter.

Referenced by Milter.test.TestBase.feedFile().

◆ getsymval()

def Milter.Base.getsymval (   self,
  sym 
)

Return the value of an MTA macro.

Sendmail macro names are either single chars (e.g. "j") or multiple chars enclosed in braces (e.g. "{auth_type}"). Macro names are MTA dependent. See smfi_getsymval for default sendmail macros.

Parameters
symthe macro name

References Milter.Base._ctx.

◆ header()

def Milter.Base.header (   self,
  field,
  value 
)

Called for each header field in the message body.

Parameters
fieldname decoded as ascii
valuefield value decoded as utf-8 on python3

Reimplemented in Milter.Milter.

Referenced by Milter.Base.header_bytes().

◆ header_bytes()

def Milter.Base.header_bytes (   self,
  fld,
  val 
)

Called with bytes by default global header callback.

Parameters
fldname decoded as ascii
valfield value as bytes
Since
1.0.5 Converts from utf-8 to unicode with surrogate escape. Can be overriden to pass bytes to the header callback instead, e.g. by assignment:
  mymilter.header_bytes = mymilter.header
 
The @decode('bytes') decorator will also do this.

References Milter.Base.header(), Milter.Milter.header(), and Milter.Base.header_bytes.

Referenced by Milter.test.TestBase.feedFile(), and Milter.Base.header_bytes().

◆ hello()

def Milter.Base.hello (   self,
  hostname 
)

Called when the SMTP client says HELO.

Returning REJECT prevents progress until a valid HELO is provided; this almost always results in terminating the connection.

Reimplemented in Milter.Milter.

Referenced by Milter.test.TestBase.connect().

◆ negotiate()

def Milter.Base.negotiate (   self,
  opts 
)

Negotiate milter protocol options.

Called by the xffi_negotiate callback. This is an advanced callback, do not override unless you know what you are doing. Most negotiation can be done simply by using the supplied class and function decorators. Options are passed as a list of 4 32-bit ints which can be modified and are passed back to libmilter on return. Default negotiation sets P_NO* and P_NR* for callbacks marked @nocallback and @noreply respectively, leaves all actions enabled, and enables Milter.SKIP. The @enable_protocols class decorator can customize which protocol steps are implemented.

Parameters
optsa modifiable list of 4 ints with negotiated options
Since
0.9.2

References Milter.Base._actions, Milter.Base._protocol, Milter.test.TestBase._protocol, Milter.testctx.TestCtx._protocol, Milter.Base.protocol_mask(), Milter.Base.setsymlist(), milter.milterContext.setsymlist(), Milter.test.TestBase.setsymlist(), and Milter.testctx.TestCtx.setsymlist().

Referenced by Milter.test.TestBase.connect().

◆ progress()

def Milter.Base.progress (   self)

Tell the MTA to wait a bit longer.

Calls smfi_progress.
Resets timeouts in the MTA that detect a "hung" milter.

References Milter.Base._ctx.

◆ protocol_mask()

def Milter.Base.protocol_mask (   klass)

Return mask of SMFIP_N* protocol option bits to clear for this class The @nocallback and @noreply decorators set the milter_protocol function attribute to the protocol mask bit to pass to libmilter, causing that callback or its reply to be skipped.

Overriding a method creates a new function object, so that milter_protocol defaults to 0. Libmilter passes the protocol bits that the current MTA knows how to skip. We clear the ones we don't want to skip. The negation is somewhat mind bending, but it is simple.

Since
0.9.2

Referenced by Milter.Base.negotiate().

◆ quarantine()

def Milter.Base.quarantine (   self,
  reason 
)

Quarantine the message.

Calls smfi_quarantine.
When quarantined, a message goes into the mailq as if to be delivered, but delivery is deferred until the message is unquarantined. The Milter.QUARANTINE action flag must be set.

May be called from eom callback only.

Parameters
reasona string describing the reason for quarantine
Exceptions
DisabledActionif QUARANTINE is not enabled

References Milter.Base._actions, and Milter.Base._ctx.

◆ replacebody()

def Milter.Base.replacebody (   self,
  body 
)

Replace the message body.

Calls smfi_replacebody.
The entire message body must be replaced.
Call repeatedly with blocks of data until the entire body is transferred. The Milter.MODBODY action flag must be set.

May be called from eom callback only.

Parameters
bodya chunk of body data
Exceptions
DisabledActionif MODBODY is not enabled

References Milter.Base._actions, and Milter.Base._ctx.

◆ setreply()

def Milter.Base.setreply (   self,
  rcode,
  xcode = None,
  msg = None,
ml 
)

Set the SMTP reply code and message.

If the MTA does not support setmlreply, then only the first msg line is used. Any '%' in a message line must be doubled, or libmilter will silently ignore the setreply. Beginning with 0.9.6, we test for that case and throw ValueError to avoid head scratching. What will really irritate you, however, is that if you carefully double any '%', your message will be sent - but with the '%' still doubled! See smfi_setreply for more information.

Parameters
rcodeThe three-digit (RFC 821/2821) SMTP reply code as a string. rcode cannot be None, and must be a valid 4XX or 5XX reply code.
xcodeThe extended (RFC 1893/2034) reply code. If xcode is None, no extended code is used. Otherwise, xcode must conform to RFC 1893/2034.
msgThe text part of the SMTP reply. If msg is None, an empty message is used.
mlOptional additional message lines.

References Milter.Base._ctx.

◆ setsymlist()

def Milter.Base.setsymlist (   self,
  stage,
macros 
)

Tell the MTA which macro names will be used.

This information can reduce the size of messages received from sendmail, and hence could reduce bandwidth between sendmail and your milter where that is a factor. The Milter.SETSYMLIST action flag must be set. The protocol stages are M_CONNECT, M_HELO, M_ENVFROM, M_ENVRCPT, M_DATA, M_EOM, M_EOH.

May only be called from negotiate callback. Hence, this is an advanced feature. Use the @symlist function decorator to conviently set the macros used by a callback.

Since
0.9.8, previous version was misspelled!
Parameters
stagethe protocol stage to set to macro list for, one of the M_* constants defined in Milter
macrosspace separated and/or lists of strings

References Milter.Base._actions, and Milter.Base._ctx.

Referenced by Milter.Base.negotiate().

◆ unknown()

def Milter.Base.unknown (   self,
  cmd 
)

Called when the SMTP client issues an unknown command.

Parameters
cmdthe unknown command
Since
0.9.2

Member Data Documentation

◆ _actions

Milter.Base._actions
private

A bitmask of actions this connection has negotiated to use.

By default, all actions are enabled. High throughput milters may want to disable unused actions to increase efficiency. Some optional actions may be disabled by calling milter.set_flags(), or by overriding the negotiate callback. The bits include: ADDHDRS,CHGBODY,MODBODY,ADDRCPT,ADDRCPT_PAR,DELRCPT CHGHDRS,QUARANTINE,CHGFROM,SETSYMLIST. The Milter.CURR_ACTS bitmask is all actions known when the milter module was compiled. Application code can also inspect this field to determine which actions are available. This is especially useful in generic library code designed to work in multiple milters.

Since
0.9.2

Referenced by Milter.Base.addheader(), Milter.Base.addrcpt(), Milter.Base.chgfrom(), Milter.Base.chgheader(), Milter.Base.delrcpt(), Milter.Base.negotiate(), Milter.Base.quarantine(), Milter.Base.replacebody(), Milter.test.TestBase.setreply(), and Milter.Base.setsymlist().

◆ _protocol

Milter.Base._protocol
private

A bitmask of protocol options this connection has negotiated.

An application may inspect this variable to determine which protocol steps are supported. Options of interest to applications: the SKIP result code is allowed only if the P_SKIP bit is set, rejected recipients are passed to the milter application only if the P_RCPT_REJ bit is set, and header values are sent and received with leading spaces (in the continuation lines) intact if the P_HDR_LEADSPC bit is set (so that the application can customize indenting).

The P_N* bits should be negotiated via the @noreply and @nocallback method decorators, and P_RCPT_REJ, P_HDR_LEADSPC should be enabled using the enable_protocols class decorator.

The bits include: P_RCPT_REJ P_NR_CONN P_NR_HELO P_NR_MAIL P_NR_RCPT P_NR_DATA P_NR_UNKN P_NR_EOH P_NR_BODY P_NR_HDR P_NOCONNECT P_NOHELO P_NOMAIL P_NORCPT P_NODATA P_NOUNKNOWN P_NOEOH P_NOBODY P_NOHDRS P_HDR_LEADSPC P_SKIP (all under the Milter namespace).

Since
0.9.2

Referenced by Milter.Base.negotiate(), and Milter.testctx.TestCtx.progress().


The documentation for this class was generated from the following file: