I have a pretty large email class that constructs & sends various emails with mime, attachments etc.
Everything works fine but it is called from my main loop and the sendmail method using smtplib can sometimes block for several seconds because of issues at the other end.
I want to run the code in a new thread so my main loop can keep trucking.
I have tried two approaches without success:
Calling my class using a Thread
Inherit my V1 class from Thread
Neither stop the blocking. Below is a working skeleton of my class (V1) and what I have tried. Success would be to see "Done" appear immediately after "Starting" instead of waiting the 3 seconds for sendmail to finish. Hoping there is an easy way to do this...
from time import sleep
from threading import Thread
class EMailv1():
def __init__(self):
self._from_address = '[email protected]'
self._to_addresslist = []
def buildmessage(self, **kwargs):
message ={}
return message
@staticmethod
def sendmail(message):
sleep(5)
return
class EMailv2(Thread):
def __init__(self):
Thread.__init__(self)
self._from_address = '[email protected]'
self._to_addresslist = []
def run(self):
pass
def buildmessage(self, **kwargs):
message ={}
return message
@staticmethod
def sendmail( message):
sleep(3)
return
if __name__ == "__main__":
print('Starting V1 class send in current manner, which blocks if smtplib cannot deliver mail')
email =EMailv1()
msg = email.buildmessage(a='a',b='b')
email.sendmail(msg)
print('v1 Done after sendmail sleep finishes')
print('Starting threaded call to send V1 class')
email = EMailv1()
msg = email.buildmessage(a='a',b='b')
t = Thread(target=email.sendmail(msg))
t.start()
print('Threaded call of V1 Done after sendmail sleep finishes')
print('Starting V2 class inheriting Thread')
email = EMailv2()
msg = email.buildmessage(a='a',b='b')
email.start()
email.sendmail(msg)
print('V2 Done after sendmail sleep finishes')
In your second version, instead of
you should do
In the way you wrote, it is evaluating
email.sendmail(msg)
before constructing the thread, that's why you see that you wait 5 seconds before proceeding.Instead you should pass the thread a target function and it's args separately, without evaluating them.
Here is a fixed and minimalized version:
Output:
With that said, I'd also suggest you to take a look at some abstractions provided in Python for doing multithreaded work. For instance, take a look at features like ThreadPoolExecutor - these are usually preferable to working directly with
Thread
s.