Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
P
pymilter
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Deploy
Releases
Container registry
Model registry
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
misc
pymilter
Commits
6577e40b
Commit
6577e40b
authored
17 years ago
by
Stuart Gathman
Browse files
Options
Downloads
Patches
Plain Diff
Build pymilter as separate package.
parent
04eeeab2
No related branches found
No related tags found
No related merge requests found
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
milter-template.py
+155
-0
155 additions, 0 deletions
milter-template.py
milter.spec
+14
-3
14 additions, 3 deletions
milter.spec
setup.py
+1
-1
1 addition, 1 deletion
setup.py
with
170 additions
and
4 deletions
milter-template.py
0 → 100644
+
155
−
0
View file @
6577e40b
## 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
()
This diff is collapsed.
Click to expand it.
milter.spec
+
14
−
3
View file @
6577e40b
%define name milter
%define version 0.8.
7
%define name
py
milter
%define version 0.8.
8
%define release 1
# what version of RH are we building for?
%define redhat7 0
...
...
@@ -37,7 +37,7 @@ Prefix: %{_prefix}
Vendor: Stuart D. Gathman <stuart@bmsi.com>
Packager: Stuart D. Gathman <stuart@bmsi.com>
Url: http://www.bmsi.com/python/milter.html
Requires: %{python} >= 2.4, sendmail >= 8.13
, pyspf >= 2.0.4
Requires: %{python} >= 2.4, sendmail >= 8.13
%ifos Linux
Requires: chkconfig
%endif
...
...
@@ -49,6 +49,14 @@ attach to sendmail's libmilter functionality. Additional python
modules provide for navigating and modifying MIME parts, sending
DSNs, and doing CBV.
%package -n milter
Group: Applications/System
Summary: BMS spam and reputation milter
Requires: pyspf >= 2.0.4
%description -n milter
An effective spam filtering and reputation tracking mail application.
%prep
%setup
#patch -p0 -b .bms
...
...
@@ -158,6 +166,9 @@ rm -rf $RPM_BUILD_ROOT
%files -f INSTALLED_FILES
%defattr(-,root,root)
%doc README HOWTO ChangeLog NEWS TODO CREDITS sample.py milter-template.py
%files -n milter
%defattr(-,root,root)
/etc/logrotate.d/milter
/etc/cron.daily/milter
%ifos aix4.1
...
...
This diff is collapsed.
Click to expand it.
setup.py
+
1
−
1
View file @
6577e40b
...
...
@@ -15,7 +15,7 @@ if sys.version < '2.2.3':
DistributionMetadata
.
download_url
=
None
# NOTE: importing Milter to obtain version fails when milter.so not built
setup
(
name
=
"
milter
"
,
version
=
'
0.8.8
'
,
setup
(
name
=
"
py
milter
"
,
version
=
'
0.8.8
'
,
description
=
"
Python interface to sendmail milter API
"
,
long_description
=
"""
\
This is a python extension module to enable python scripts to
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment