Skip to content
Snippets Groups Projects
Select Git revision
  • 7a66ed9c8a715d9aebfd39904623425f0072cf85
  • master default protected
  • version2
  • update_bulma_fontawesome
  • privacy_notification
  • specify_target_asset_app
  • v2.2.24
  • v2.3.0
  • v2.2.23
  • v2.2.22
  • v2.2.21
  • v2.2.20
  • v2.2.19
  • v2.2.18
  • v2.2.17
  • v2.2.16
  • v2.2.15
  • v2.2.14
  • v2.2.13
  • v2.2.12
  • v2.2.11
  • v2.2.10
  • v2.2.9
  • v2.2.8
  • v2.2.7
  • v2.2.6
26 results

setup.py

Blame
  • milter-template.py 4.63 KiB
    ## To roll your own milter, create a class that extends Milter.  
    #  See the pymilter project at http://bmsi.com/python/milter.html
    #  based on Sendmail's milter API http://www.milter.org/milter_api/api.html
    #  This code is open-source on the same terms as Python.
    
    ## Milter calls methods of your class at milter events.
    ## Return REJECT,TEMPFAIL,ACCEPT to short circuit processing for a message.
    ## You can also add/del recipients, replacebody, add/del headers, etc.
    
    import Milter
    import StringIO
    import time
    import email
    from socket import AF_INET, AF_INET6
    
    def parse_addr(t):
      """Split email into user,domain.
    
      >>> parse_addr('user@example.com')
      ['user', 'example.com']
      >>> parse_addr('"user@example.com"')
      ['user@example.com']
      >>> parse_addr('"user@bar"@example.com')
      ['user@bar', 'example.com']
      >>> parse_addr('foo')
      ['foo']
      """
      if t.startswith('<') and t.endswith('>'): t = t[1:-1]
      if t.startswith('"'):
        if t.endswith('"'): return [t[1:-1]]
        pos = t.find('"@')
        if pos > 0: return [t[1:pos],t[pos+2:]]
      return t.split('@')
    
    class myMilter(Milter.Milter):
    
      def __init__(self):  # A new instance with each new connection.
        self.id = Milter.uniqueID()  # Integer incremented with each call.
    
      # each connection runs in its own thread and has its own myMilter
      # instance.  Python code must be thread safe.  This is trivial if only stuff
      # in myMilter instances is referenced.
      def connect(self, IPname, family, hostaddr):
        # (self, 'ip068.subnet71.example.com', AF_INET, ('215.183.71.68', 4720) )
        # (self, 'ip6.mxout.example.com', AF_INET6,
        #	('3ffe:80e8:d8::1', 4720, 1, 0) )
        self.IP = hostaddr[0]
        self.port = hostaddr[1]
        if family == AF_INET6:
          self.flow = hostaddr[2]
          self.scope = hostaddr[3]
        else:
          self.flow = None
          self.scope = None
        self.IPname = IPname  # Name from a reverse IP lookup
        self.H = None
        self.fp = None
        self.receiver = self.getsymval('j')
        self.log("connect from %s at %s" % (IPname, hostaddr) )
        
        return Milter.CONTINUE
    
    
      ##  def hello(self,hostname):
      def hello(self, heloname):
        # (self, 'mailout17.dallas.texas.example.com')
        self.H = heloname
        self.log("HELO %s" % heloname)
        if heloname.find('.') < 0:	# illegal helo name
          # NOTE: example only - too many real braindead clients to reject on this
          self.setreply('550','5.7.1','Sheesh people!  Use a proper helo name!')
          return Milter.REJECT
          
        return Milter.CONTINUE
    
      ##  def envfrom(self,f,*str):
      def envfrom(self, mailfrom, *str):
        self.F = mailfrom
        self.R = []  # list of recipients
        self.fromparms = Milter.dictfromlist(str)	# ESMTP parms
        self.user = self.getsymval('{auth_authen}')	# authenticated user
        self.log("mail from:", mailfrom, *str)
        self.fp = StringIO.StringIO()
        self.canon_from = '@'.join(parse_addr(mailfrom))
        self.fp.write('From %s %s\n' % (self.canon_from,time.ctime()))
        return Milter.CONTINUE
    
    
      ##  def envrcpt(self, to, *str):
      def envrcpt(self, recipient, *str):
        rcptinfo = to,Milter.dictfromlist(str)
        self.R.append(rcptinfo)
        
        return Milter.CONTINUE
    
    
      def header(self, name, hval):
        self.fp.write("%s: %s\n" % (name,hval))	# add header to buffer
        return Milter.CONTINUE
    
    
      def eoh(self):
        self.fp.write("\n")				# terminate headers
        return Milter.CONTINUE
    
    
      def body(self, chunk):
        self.fp.write(chunk)
        return Milter.CONTINUE
    
    
      def eom(self):
        self.fp.seek(0)
        msg = email.message_from_file(self.fp)
        self.setreply('250','2.5.1','Grokked by pymilter')
        # many milter functions can only be called from eom()
        # example of adding a Bcc:
        self.addrcpt('<%s>' % 'spy@example.com')
        return Milter.ACCEPT
    
    
      def close(self):
        # always called, even when abort is called.  Clean up
        # any external resources here.
        return Milter.CONTINUE
    
      def abort(self):
        # client disconnected prematurely
        return Milter.CONTINUE
    
      ## === Support Functions ===
    
      def log(self,*msg):
        print "%s [%d]" % (time.strftime('%Y%b%d %H:%M:%S'),self.id),
        # 2005Oct13 02:34:11 [1] msg1 msg2 msg3 ...
        for i in msg: print i,
        print
    
    
    ## ===
        
    def main():
      # Register to have the Milter factory create instances of your class:
      Milter.factory = myMilter
      flags = Milter.CHGBODY + Milter.CHGHDRS + Milter.ADDHDRS
      flags += Milter.ADDRCPT
      flags += Milter.DELRCPT
      Milter.set_flags(flags)       # tell Sendmail which features we use
      print "%s milter startup" % time.strftime('%Y%b%d %H:%M:%S')
      sys.stdout.flush()
      Milter.runmilter("pythonfilter",socketname,timeout)
      print "%s bms milter shutdown" % time.strftime('%Y%b%d %H:%M:%S')
    
    if __name__ == "__main__":
      main()