forked from ont/slacker
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhandler.py
127 lines (109 loc) · 4.52 KB
/
handler.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import os
import re
import yaml
import base64
import binascii
import slack
import slack.chat
import html2text
import email
import requests
from aiosmtpd.handlers import Message
from hashlib import sha256
from base64 import b64encode, b64decode
class MessageHandler(Message):
def __init__(self, *args, **kargs):
Message.__init__(self, *args, **kargs)
config = os.getenv('CONFIG', '/etc/slacker/config.yml')
print(config)
if not os.path.exists(config):
print('Config doesn\'t exists!')
exit(1)
self.config = yaml.safe_load(open(config))
def email2text(data):
body = email.message_from_bytes(data).get_payload()
h = html2text.HTML2Text()
h.ignore_tables = True
h.ignore_links = True
h.ignore_images = True
return re.sub(r'\n\s*\n', '\n\n', h.handle(body))
def handle_message(self, message):
""" This method will be called by aiosmtpd server when new mail will
arrive.
"""
options = self.process_rules(message)
print('matched', options)
parsedMessage = email.message_from_string(message.as_string())
body = ""
if parsedMessage.is_multipart():
if options['debug']:
print("Message is a multipart")
for part in parsedMessage.walk():
ctype = part.get_content_type()
cdispo = str(part.get('Content-Disposition'))
if options['debug']:
print("Content type is: " + ctype)
# skip any text/plain (txt) attachments
if ctype.startswith('text/plain') and 'attachment' not in cdispo:
if options['debug']:
print("Matched content type text/plain")
body = part.get_payload(decode=True) # decode
break
if ctype.startswith('text/html') and 'attachment' not in cdispo:
if options['debug']:
print("Matched content type text/html")
body = MessageHandler.email2text(part.get_payload(decode=True)) # decode
break
# not multipart - i.e. plain text, no attachments, keeping fingers crossed
else:
ctype = message.get_content_type()
cdispo = str(message.get('Content-Disposition'))
if ctype.startswith('text/plain') and 'attachment' not in cdispo:
if options['debug']:
print("Matched non-multipart content type text/plain")
body = message.get_payload(decode=True) # decode
elif ctype.startswith('text/html') and 'attachment' not in cdispo:
if options['debug']:
print("Matched non-multipart content type text/html")
body = MessageHandler.email2text(message.get_payload(decode=True)) # decode
else:
if options['debug']:
print("Did not match a non-multipart content type")
body = parsedMessage.get_payload(decode=True)
if options['debug']:
#print(body)
#self.send_to_slack('DEBUG: ' + str(body), **options)
self.send_to_slack('DEBUG: ' + str(parsedMessage), **options)
else:
try:
self.send_to_slack(body, **options)
except slack.exception.SlackError:
# Send whole object only if Slack throws error
self.send_to_slack(str(parsedMessage), **options)
def process_rules(self, message):
""" Check every rule from config and returns options from matched
"""
default = self.config['default']
fields = {
'from': message['From'],
'to': message['To'],
'subject': message['Subject'],
'body': message.get_payload()
}
print(fields)
for rule in self.config['rules']:
tests = (re.match(rule[field], str(value)) for field, value in fields.items() if field in rule)
if all(tests):
options = default.copy()
options.update(rule['options'])
return options
return default
def send_to_slack(self, text, **options):
print('sending to slack', text, options)
slack.api_token = options['slack_token']
slack.chat.post_message(
options['channel'],
text,
username=options['username'],
icon_url=options['icon_url']
)