msg[name'join(valuerecip list(set(recip)fulltext msg as_string( ebcc gets mailno hdr add commas between cc eremove duplicates generate formatted msg sendmail call raises except if all tos failedor returns failed tos dict for any that failed self trace('sending to str(recip)self trace(fulltext[:self tracesize]smtp calls connect server smtplib smtp(self smtpservernamethis may fail too self getpassword(if srvr requires self authenticateserver(serverlogin in subclass tryfailed server sendmail(fromrecipfulltextexcept or dict exceptserver close( equit may hangraise reraise except elseserver quit(connect send ok self savesentmessage(fulltextsavemailseparator edo this first if failedclass someaddrsfailed(exception)pass raise someaddrsfailed('failed addrs:% \nfailedself trace('send exit'def addattachments(selfmainmsgbodytextattachesbodytextencodingattachesencodings)""format multipart message with attachmentsuse unicode encodings for text parts if passed""add main text/plain part msg mimetext(bodytext_charset=bodytextencodingmainmsg attach(msgadd attachment parts encodings attachesencodings or (['us-ascii'len(attaches)for (filenamefileencodein zip(attachesencodings)filename may be absolute or relative if not os path isfile(filename)skip dirsetc continue guess content type from file extensionignore encoding contypeencoding mimetypes guess_type(filenameif contype is none or encoding is not noneno guesscompressedcontype 'application/octet-streamuse generic default self trace('adding contypebuild sub-message of appropriate kind maintypesubtype contype split('/' if maintype ='text' etext needs encoding if fix_text_required(fileencode)requires str or bytes data open(filename' 'encoding=fileencodethe mailtools utility package