################################################## # Spyce mail module # Copyright (c) 2002 Adrien Plisson. # # SPYCE is Copyright (c) 2002 Rimon Barr. # Refer to spyce.py ################################################## from spyceModule import spyceModule import smtplib import email import types import string import quopri class mail(spyceModule): def start(self): pass def init(self, *args, **kwargs): if args != () or kwargs != {}: self.setServer(*args, **kwargs) def finish(self, error=None): pass def setServer(self, host, port=25, user=None, password=None): self.host = host self.port= port self.user = user self.password = password def send(self, from_field, to_field, subject_field, content, cc_field=None, bcc_field=None): #parse arguments from_field = _parse_addrs(from_field) to_field = _parse_addrs(to_field) if cc_field != None: cc_field = _parse_addrs(cc_field) if bcc_field != None: bcc_field = _parse_addrs(bcc_field) #compose the mail msg = _build_main_message(from_field, to_field, subject_field, content, cc_field).as_string() #build the sender and recipients lists sender = from_field[0] if cc_field == None: recipients = to_field else: recipients = to_field + cc_field sender= _unparse_addr(sender) for i in range(len(recipients)): recipients[i] = _unparse_addr(recipients[i]) #establish the connection con = smtplib.SMTP(self.host, self.port) if self.user != None and self.password != None: con.login(self.user, self.password) #send the mail first to the recipients in the to and cc fields con.sendmail(sender, recipients, msg) #then we send it for each recipient in the bcc field if bcc_field != None: for recipient in bcc_field: con.sendmail(sender, recipient, msg) #close the connection con.quit() def _parse_addrs(addrs): if type(addrs) == types.ListType: return map(_parse_addr, addrs) else: return [_parse_addr(addrs)] def _parse_addr(addr): if type(addr) in types.StringTypes: return email.Utils.parseaddr(addr) elif type(addr) == types.TupleType: return addr def _unparse_addrs(addrs): return string.join(map(_unparse_addr, addrs), ', ') def _unparse_addr(addr): return email.Utils.dump_address_pair(addr) def _build_main_message(from_field, to_field, subject_field, content, cc_field=None): msg = email.Message.Message() msg['From'] = _unparse_addrs(from_field) msg['To'] = _unparse_addrs(to_field) if cc_field != None: msg['Cc'] = _unparse_addrs(cc_field) msg['Subject'] = _encode_field(subject_field) msg['MIME-Version'] = '1.0' #if content is a dictionnary (with content, type, encoding and disposition) if type(content) == types.DictType: msg['Content-Type'] = content['type'] #if we have subparts if type(content['content']) == types.ListType: for submsg in content['content']: msg.attach(_build_message(submsg)) #if we don't have any subpart else: #if the content is a string if type(content['content']) in types.StringTypes: msg.attach(content['content']) #or if it's an open file else: msg.attach(content['content'].read()) #if we have an encoding, then we encode if content.has_key('encoding'): msg = _encode_message(msg, content['encoding']) #we allow to specify some additional fields if content.has_key('additional_fields'): for field in content['additional_fields']: msg[field] = content['additional_fields'][field] #if the content is a list then we have subparts elif type(content) == types.ListType: msg['Content-Type'] = 'multipart/mixed' for submsg in content: msg.attach(_build_message(submsg)) #if content is a string, then we dump it as is elif type(content) in types.StringTypes: msg.attach(content) #in other cases, we consider it's an open file else: msg.attach(content.read()) return msg def _build_message(content): msg = email.Message.Message() #if content is a dictionnary (with content, type, encoding and disposition) if type(content) == types.DictType: msg['Content-Type'] = content['type'] #if we have subparts if type(content['content']) == types.ListType: for submsg in content['content']: msg.attach(_build_message(submsg)) #if we don't have any subpart else: #if the content is a string if type(content['content']) in types.StringTypes: msg.attach(content['content']) #or if it's an open file else: msg.attach(content['content'].read()) #if we have an encoding, then we encode if content.has_key('encoding'): msg = _encode_message(msg, content['encoding']) #we allow to specify some additional fields if content.has_key('additional_fields'): for field in content['additional_fields']: msg[field] = content['additional_fields'][field] #if the content is a list then we have subparts elif type(content) == types.ListType: msg['Content-Type'] = 'multipart/mixed' for submsg in content: msg.attach(_build_message(submsg)) #if content is a string, then we dump it as is elif type(content) in types.StringTypes: msg.attach(content) #in other cases, we consider it's an open file else: msg.attach(content.read()) return msg def _encode_field(field): if quopri.encodestring(field) == field: return field else: return email.Utils.encode(field) def _encode_message(msg, encoding): if encoding == 'quoted-printable': email.Encoders.encode_quopri(msg) elif encoding == 'base64': email.Encoders.encode_base64(msg) elif encoding == '7bit' or encoding == '8bit': email.Encoders.encode_7or8bit(msg) return msg