From murthy at barc.gov.in Mon May 6 08:17:15 2013 From: murthy at barc.gov.in (C.S.R.C.Murthy) Date: Mon, 06 May 2013 17:47:15 +0530 Subject: [Pymilter] Variables across call backs Message-ID: <51879F4B.9010203@barc.gov.in> Hi, I would like to know whether it is possible to define a variable in a call back and access it in next call back?. How the defined variable will be unique for different SMTP connections? -murthy -------------- next part -------------- A non-text attachment was scrubbed... Name: murthy.vcf Type: text/x-vcard Size: 254 bytes Desc: not available URL: From stuart at bmsi.com Mon May 6 14:39:32 2013 From: stuart at bmsi.com (Stuart D Gathman) Date: Mon, 06 May 2013 14:39:32 -0400 Subject: [Pymilter] Variables across call backs In-Reply-To: <51879F4B.9010203@barc.gov.in> References: <51879F4B.9010203@barc.gov.in> Message-ID: <5187F8FD.2090201@bmsi.com> On 05/06/2013 08:16 AM, C.S.R.C.Murthy expounded in part: > I would like to know whether it is possible to define a variable in a > call back and access it in next call back?. How the defined variable > will be unique for different SMTP connections? > A new python object is created for each SMTP connection. Like any other python class instance, you create instance variables by assigning them. Here is an example from spfmilter.py (in the milter package): class spfMilter(Milter.Base): "Milter to check SPF. Each connection gets its own instance." def log(self,*msg): syslog.syslog('[%d] %s' % (self.id,' '.join([str(m) for m in msg]))) ..... def hello(self,hostname): self.hello_name = hostname self.log("hello from %s" % hostname) if not self.internal_connection: # Allow illegal HELO from internal network, some email enabled copier/fax # type devices (Toshiba) have broken firmware. if ip4re.match(hostname): self.log("REJECT: numeric hello name:",hostname) self.setreply('550','5.7.1','hello name cannot be numeric ip') return Milter.REJECT return Milter.CONTINUE ------------------8<-----------------8<---------------------------------- Instance variable hello_name is available for all subsequent callbacks. If you need to share between connection, then use a global variable, BUT be careful as each SMTP connection runs in its own thread! From abhijeet.1989 at gmail.com Thu May 9 07:49:38 2013 From: abhijeet.1989 at gmail.com (Abhijeet Rastogi) Date: Thu, 9 May 2013 17:19:38 +0530 Subject: [Pymilter] Change Body from header in a mail (newbie question) Message-ID: Hi all, As we know, there are two "from" in a mail. The actual envelope mailfrom and the body from. I'm trying to change body "from" whenver "envelope mailfrom" and "body from" don't match. For that, I picked the official example. http://pythonhosted.org/pymilter/milter-template_8py-example.html and edited the below code. def header(self, name, hval): if name == "From": if self.F != hval: self.log("<" + hval.strip("<>") + "via " + self.F.strip("<>") + ">") hval = hval + "via" + self.F self.fp.write("%s: %s\n" % (name,hval)) # add header to buffer return Milter.CONTINUE I can see by adding "self.log" statements that the header is actually being changed but when I receive the mail, I still see the original body from. Why can that be so? I even tried the "Milter.set_flags(Milter.CURR_ACTS)", still it's not changing the body from. It's my first milter writing experience and I'm stuck at this. Any help would be highly appreciated. -- Regards, Abhijeet Rastogi (shadyabhi) http://blog.abhijeetr.com From stuart at bmsi.com Fri May 10 00:43:16 2013 From: stuart at bmsi.com (Stuart D Gathman) Date: Fri, 10 May 2013 00:43:16 -0400 (EDT) Subject: [Pymilter] Change Body from header in a mail (newbie question) In-Reply-To: References: Message-ID: On May 9, Abhijeet Rastogi transmitted in part: > As we know, there are two "from" in a mail. The actual envelope > mailfrom and the body from. I'm trying to change body "from" whenver > "envelope mailfrom" and "body from" don't match. A questionable goal, but certainly easy. > For that, I picked the official example. > http://pythonhosted.org/pymilter/milter-template_8py-example.html and > edited the below code. > > def header(self, name, hval): > if name == "From": > if self.F != hval: > self.log("<" + hval.strip("<>") + "via " + self.F.strip("<>") + ">") > hval = hval + "via" + self.F > > self.fp.write("%s: %s\n" % (name,hval)) # add header to buffer > return Milter.CONTINUE > > I can see by adding "self.log" statements that the header is actually > being changed but when I receive the mail, I still see the original > body from. Why can that be so? I even tried the > "Milter.set_flags(Milter.CURR_ACTS)", still it's not changing the body > from. Because you are only changing the copy of the header in your internal buffer. I added that buffer to the example because people kept asking, "How do I collect all the headers to make a complete email (e.g. for archiving)?" > It's my first milter writing experience and I'm stuck at this. Any > help would be highly appreciated. Use chgheader to change the header in the MTA: http://pythonhosted.org/pymilter/classMilter_1_1Base.html#a2debae177f22c9ae4c53644280a2cd10 Note that chgheader can only be called from eom. In the bms.py milter, I use a helper method: # addheader can only be called from eom(). This accumulates added # headers which can then be applied by alter_headers() in eom(). def add_header(self,name,val,idx=-1): self.new_headers.append((name,val,idx)) self.log('%s: %s' % (name,val)) Additional hooks may be needed in eoh() to add the new headers to your internal buffer, if used. I did not implement chg_header (or even fully implement add_header), but the same idea applies. You might consider it for future milters. In your case, I would just set self.from_header = None in envfrom(), and set it to the desired value according to your logic if it needs changing. Then in eom(): def eom(): if self.from_header: self.chgheader('from',0,self.from_header) ... From abhijeet.1989 at gmail.com Fri May 10 02:53:23 2013 From: abhijeet.1989 at gmail.com (Abhijeet Rastogi) Date: Fri, 10 May 2013 12:23:23 +0530 Subject: [Pymilter] Change Body from header in a mail (newbie question) In-Reply-To: References: Message-ID: Hi Stuart, Thanks for the reply. I finally got what I wanted, thanks to you. May I know where is it documented that what all functions can only be called from "eom" function? On Fri, May 10, 2013 at 10:13 AM, Stuart D Gathman wrote: > On May 9, Abhijeet Rastogi transmitted in part: > > >> As we know, there are two "from" in a mail. The actual envelope >> mailfrom and the body from. I'm trying to change body "from" whenver >> "envelope mailfrom" and "body from" don't match. > > > A questionable goal, but certainly easy. > > >> For that, I picked the official example. >> http://pythonhosted.org/pymilter/milter-template_8py-example.html and >> edited the below code. >> >> def header(self, name, hval): >> if name == "From": >> if self.F != hval: >> self.log("<" + hval.strip("<>") + "via " + self.F.strip("<>") + >> ">") >> hval = hval + "via" + self.F >> >> self.fp.write("%s: %s\n" % (name,hval)) # add header to buffer >> return Milter.CONTINUE >> >> I can see by adding "self.log" statements that the header is actually >> being changed but when I receive the mail, I still see the original >> body from. Why can that be so? I even tried the >> "Milter.set_flags(Milter.CURR_ACTS)", still it's not changing the body >> from. > > > Because you are only changing the copy of the header in your internal > buffer. I added that buffer to the example because people kept asking, > "How do I collect all the headers to make a complete email (e.g. for > archiving)?" > > >> It's my first milter writing experience and I'm stuck at this. Any >> help would be highly appreciated. > > > Use chgheader to change the header in the MTA: > > http://pythonhosted.org/pymilter/classMilter_1_1Base.html#a2debae177f22c9ae4c53644280a2cd10 > > Note that chgheader can only be called from eom. In the bms.py milter, > I use a helper method: > > # addheader can only be called from eom(). This accumulates added > # headers which can then be applied by alter_headers() in eom(). > def add_header(self,name,val,idx=-1): > self.new_headers.append((name,val,idx)) > self.log('%s: %s' % (name,val)) > > Additional hooks may be needed in eoh() to add the new headers to your > internal buffer, if used. > > I did not implement chg_header (or even fully implement add_header), but > the same idea applies. You might consider it for future milters. > > In your case, I would just set self.from_header = None in envfrom(), > and set it to the desired value according to your logic if it needs > changing. Then in eom(): > > def eom(): > if self.from_header: > self.chgheader('from',0,self.from_header) > ... -- Regards, Abhijeet Rastogi (shadyabhi) http://blog.abhijeetr.com From abhijeet.1989 at gmail.com Mon May 13 03:43:55 2013 From: abhijeet.1989 at gmail.com (Abhijeet Rastogi) Date: Mon, 13 May 2013 13:13:55 +0530 Subject: [Pymilter] Dataproxy proxy in pymilter Message-ID: Hi, Before wanting to have my answer, I need to understand how a milter works. So, it it like when a new mail is in queue, one instance of milter script is spawned for each mail? I need to have a functionality like having a python object common to all milter instances. The reason I want to do this is because I need a persistent database connection to postgres to do some queries and fetch data. Doing a connection connect, query fetch and connection close each and every time in a function will be horribly inefficient in my opinion. For a case I like this, how is it done in milters? I've seem milters that use remote servers for virus detection so we might have functionality like that though I've no idea. Hope my question makes sense. Thanks a lot in advance. -- Regards, Abhijeet Rastogi (shadyabhi) http://blog.abhijeetr.com From stuart at bmsi.com Mon May 13 15:21:36 2013 From: stuart at bmsi.com (Stuart D Gathman) Date: Mon, 13 May 2013 15:21:36 -0400 (EDT) Subject: [Pymilter] Dataproxy proxy in pymilter In-Reply-To: References: Message-ID: On May 13, Abhijeet Rastogi transmitted in part: > Before wanting to have my answer, I need to understand how a milter > works. So, it it like when a new mail is in queue, one instance of > milter script is spawned for each mail? No. One instance of a user class derived from Milter.Base is created for each SMTP connection to the MTA. Each connection also has its own Thread. > I need to have a functionality like having a python object common to > all milter instances. The reason I want to do this is because I need a > persistent database connection to postgres to do some queries and > fetch data. So create a global object. Caveat: since each SMTP connection is its own thread, you need to wrap non-reentrant global objects with something like: import thread my_lock = thread.allocate_lock() my_global = MakeMyGlobalObject() class MyMilter(Milter.Base): # callback picked at random def hello(name): my_lock.acquire() my_global.frobigate(name) my_lock.release() ... Another approach is to use the multiprocessing or threading module as illustrated in the example milter: http://pythonhosted.org/pymilter/milter-template_8py-example.html From cifali.filipe at gmail.com Tue May 21 11:23:36 2013 From: cifali.filipe at gmail.com (Filipe Cifali) Date: Tue, 21 May 2013 12:23:36 -0300 Subject: [Pymilter] Hello, I'm new here Message-ID: I just download the PySPF/PyMilter from pip and noticed: $ python Python 2.6.4 (r264:75706, Feb 25 2010, 09:17:59) [GCC 4.3.4] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import spf Traceback (most recent call last): File "", line 1, in File "/usr/lib64/python2.6/site-packages/spf.py", line 130, in import DNS # http://pydns.sourceforge.net ImportError: No module named DNS Then I ran: $ pip show pyspf -v --- Name: pyspf Version: 2.0.7 Location: /usr/lib64/python2.6/site-packages Requires: Should pydns be in the pip package as required? Or it can be used without the installation of pydns for some other utility? I'm sorry it that was already posted. -- [ ]'s Filipe Cifali Stangler -------------- next part -------------- An HTML attachment was scrubbed... URL: From stuart at bmsi.com Tue May 21 11:51:39 2013 From: stuart at bmsi.com (Stuart D Gathman) Date: Tue, 21 May 2013 11:51:39 -0400 (EDT) Subject: [Pymilter] Hello, I'm new here In-Reply-To: References: Message-ID: On May 21, Filipe Cifali transmitted in part: > Should pydns be in the pip package as required? Or it can be used without > the installation of pydns for some other utility? pydns is a requirement for pyspf-2.0.x. It is a actually possible to use other DNS resolvers, e.g. dnspython, by replacing DNSLookup. This is actually pretty simple, taking only a few minutes work for any given resolver. Packaging a fool proof auto plugin system is not as trivial. dkimpy uses dnsplug from the still unreleased pyspf-2.1 version, which autodetects and uses any recognized DNS resolver.