forked from marcinc81/quemail
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathquemail.py
143 lines (120 loc) · 4.74 KB
/
quemail.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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# -*- coding: utf-8 -*-
'''
Simple implementation of mailer based on thread and queues. Early version.
@author: Marcin Chwalek <[email protected]>
Example of use:
# at start
qm = QueMail.get_instance()
qm.init('smtp.host.com', '[email protected]', 'SecretPassword')
qm.start()
...
# someware in app method
qm = QueMail.get_instance()
qm.send(Email(subject="Subject", text="Keep smiling :)", adr_to="[email protected]", adr_from="[email protected]"))
...
# after everything, at end of app
qm.end()
'''
import smtplib
import logging
import time
from email.mime.text import MIMEText
from email.utils import make_msgid, formatdate
from time import sleep
from Queue import Queue
from threading import Thread
log = logging.getLogger("QueMail")
class QueMail(Thread):
instance = None
def init(self, smtp_host, smtp_login, smtp_pswd, smtp_port = 25, queue_size = 100):
self._queue = Queue(queue_size)
log.info("Initializing QueMail with queue size %i. Using SMTP server: %s:%i." % (queue_size, smtp_host, smtp_port))
self.smtp_host = smtp_host
self.smtp_login = smtp_login
self.smtp_password = smtp_pswd
self.smtp_port = smtp_port
def __init__(self):
Thread.__init__(self)
self._do_quit = False
self.setName("QueMail")
self.smtp_host = None
self.smtp_login = None
self.smtp_password = None
self.smtp_port = None
self.check_interval = 5 # the number of seconds to check the queue
def end(self):
'''
Waits until all emails will be sent and after that stops thread
'''
log.info("Stopping QueMail thread...")
self._do_quit = True
self.join()
log.info("Stopped.")
def run(self):
while not self._do_quit:
if not self._queue.empty():
log.debug(u"Connecting to SMTP server: %s:%i" % (self.smtp_host, self.smtp_port))
smtp = None
try:
smtp = smtplib.SMTP()
smtp.connect(self.smtp_host, self.smtp_port)
smtp.login(self.smtp_login, self.smtp_password)
while not self._queue.empty():
t = time.time()
eml = self._queue.get()
log.info(u"Sending (qs=%i): %s" % (self._queue.qsize(), eml))
try:
msg = eml.as_rfc_message()
content = msg.as_string()
log.debug(u"with content: %s" % content)
smtp.sendmail(eml.adr_from, eml.adr_to, content)
log.warning(u"Sent (qs=%i,t=%f): %s" % (self._queue.qsize(),time.time()-t, eml))
except Exception as e:
log.error(u"Exception occured while sending email: %s" % eml)
log.exception(e)
# FIXME not good idea: when exception occured, add email at end of queue
self._queue.put(eml, False)
sleep(1)
except Exception as e:
log.exception(e)
finally:
if smtp:
smtp.quit()
sleep(self.check_interval)
def send(self, eml):
self._queue.put(eml, True, 5);
log.debug(u'Accepted (qs=%i): %s' % (self._queue.qsize(), eml))
@classmethod
def get_instance(cls):
if not cls.instance:
cls.instance = QueMail()
return cls.instance
class Email(object):
unique = 'unique-send'
def __init__(self, **props):
'''
@param adr_to: send to
@param adr_from: send from
@param subject: subject of email
@param mime_type: plain or html - only minor mime type of 'text/*'
@param text: text content of email
'''
self.text = props.get('text', '')
self.subject = props.get('subject', None)
self.adr_to = props.get('adr_to', None)
self.adr_from = props.get('adr_from', None)
self.mime_type = props.get('mime_type', 'plain')
def __str__(self):
return "Email to: %s, from: %s, sub: %s" % (self.adr_to, self.adr_from, self.subject)
def as_rfc_message(self):
'''
Creates standardized email with valid header
'''
msg = MIMEText(self.text, self.mime_type, 'utf-8')
msg['Subject'] = self.subject
msg['From'] = self.adr_from
msg['To'] = self.adr_to
msg['Date'] = formatdate()
msg['Reply-To'] = self.adr_from
msg['Message-Id'] = make_msgid(Email.unique)
return msg