Package: mailem
Mail'EmSlim, flexible, yet full-featured e-mailing library.UnicodeEasy attachmentsInline imagesE-Mail templatesTools for unit-testsMade perfect once and for all. Simple and cute :)Here'a a full example:frommailemimportMessage,Postman,Attachment,ImageAttachmentfrommailem.connectionimportSMTPConnection# Create the messagemessages=[# Message with attachmentsMessage(['kolypto@gmail.com'],u"Mail'em test",u"<b>yeah baby, it works!</b>",attachments=[Attachment(u'test.txt',open('test.txt').read())]),# Message with inline images (!)Message(['kolypto@gmail.com'],u"Mail'em test with inline images",u"Cute: <img src='cid:cute.jpg' />",# cid:<filename>attachments=[ImageAttachment('cute.jpg',open('cute.jpg').read(),'inline')]),]# Initialize a postman with SMTP connection to GMailpostman=Postman('user@gmail.com',SMTPConnection('smtp.gmail.com',587,'user@gmail.com','pass',tls=True))# Send everything we havewithpostman.connect()asc:map(c.sendmail,messages)Also seeTemplate.Table of ContentsSending MessagesMessageAttachmentImageAttachmentPostmanPostman.connectPostman.loopbackConnectionSMTPConnectionLoopbackConnectionTemplatingTemplateTemplate.set_rendererTemplate.defaultsTemplate.callTemplate.from_directoryTemplateRegistryTemplateRegistry.addTemplateRegistry.set_rendererTemplateRegistry.defaultsTemplateRegistry.getTemplateRegistry.from_directorySending MessagesMessageMessage(recipients,subject,html=None,text=None,sender=None,cc=None,bcc=None,attachments=None,reply_to=None,date=None,headers=None)Construct a Message object.Notes:Full unicode support, and Unicode is the defaultYou can providehtmlortextcontents. If both are specified -- the message will have an 'alternative' container,
so the user will receive both HTML and plaintext. The client will choose which one to display.E-Mail addresses, such asrecipientsandsender, can be specified in one of the following formats:'user@example.com': Just an e-mail address('user@example.com', u'Honored User'): email address with nameArguments:recipients: List of recipientssubject: Message subjecthtml: Message body, HTMLtext: Message body, Textsender: Sender e-mail address. If not set explicitly, the default will be used on sendcc: CC listbcc: BCC listattachments: List of attachmentsreply_to: Reply-to addressdate: Send dateheaders: Additional headersAttachmentAttachment(filename,data,content_type='application/octet-stream',disposition='attachment',headers=None)File attachment information.This can be provided to theMessageobject on construction.filename: Filename of attachmentdata: Raw file datacontent_type: File mimetypedisposition: Content-Disposition: 'attachment', 'inline', ...headers: Additional headers for the attachmentImageAttachmentImageAttachment(filename,data,disposition='attachment',headers=None)Image attachment.It guesses the Content-Type from the data streamSupports 'inline' images: images embedded in the email. Useful for templates.Once an 'inline' image is created, its filename is used for 'Content-ID', which allows to reference it in the HTML body:frommailemimportMessage,Attachment,ImageAttachmentmsg=Message(['test@example.com'],'Hello','<img src="cid:flowers.jpg" />',# Referenced with "cid:<filename>"attachments=[ImageAttachment('flowers.jpg',open('flowers.jpg').read(),'inline')])Arguments:filename: Image attachment filename. Will also become 'Content-ID' when inlined.data: The raw file dataPostmanPostman(sender,connection)Postman is the object you use to send messages through a configured Connection object.Example:frommailemimportMessage,Postmanfrommailem.connectionimportSMTPConnection# Construct the messagemsg=Message(['kolypto@gmail.com'],u"Mail'em test",u"<b>yeah baby, it works!</b>")# Create the postman (see SMTPConnection)postman=Postman('user@gmail.com',SMTPConnection(...))# Connect, and send the messagewithpostman.connect()asc:c.sendmail(msg)sender: Default sender: e-mail or (name, email).
Is used for messages which do not specify the sender address explicitly.connection: Connection object to use. See below.Postman.connectconnect()Get connected Postman context manager.Returns:mailem.postman.ConnectedPostmanPostman.loopbackloopback()Get a context manager which installs a LoopbackConnection on this postman.This allows you to record outgoing messages by mocking a Postman.
SeeLoopbackConnection.Returns:MockedPostmanContext manager which loops back outgoing messagesConnectionConnection object represents a connection to a service which can send e-mail messages for us.SMTPConnectionSMTPConnection(host,port,username,password,local_hostname=None,ssl=False,tls=False)SMTP connection.Seesmtplibfor the list of exceptions that may occur.Example:frommailemimportPostmanfrommailem.connectionimportSMTPConnectionpostman=Postman('user@gmail.com',SMTPConnection('smtp.gmail.com',587,'user@gmail.com','pass',tls=True))withpostman.connect()asc:c.sendmail(msg)Arguments:host: SMTP server hostnameport: SMTP server port number.username: User name to authenticate withpassword: Passwordlocal_hostname: FQDN of the local host for the HELO/EHLO command. WhenNone, is detected automatically.ssl: Use SSL protocol?tls: Use TLS handshake?LoopbackConnectionLoopbackConnection()Loopback connection allows to record all outgoing messages instead of sending them.You can install it manually:frommailemimportPostmanfrommailem.connectionimportLoopbackConnectionlo=LoopbackConnection()postman=Postman('user@example.com',lo)#... sendmessages=lo.get_messages()or you can mock an existing Postman withloopback()helper:frommailemimportPostmanfrommailem.connectionimportSMTPConnectionpostman=Postman('user@example.com',SMTPConnection(...))withpostman.loopback()aslo:# Sendwithpostman.connect()asc:# mocked!c.sendmail(msg)# Getsent_messages=lo.get_messages()Loopback can be installed multiple times, and only top-level loopback will catch the messages:withpostman.loopback()aslo1:withpostman.loopback()aslo2:withpostman.connect()asc:c.sendmail(msg)len(lo1)#-> 0len(lo2)#-> 1Also note thatLoopbackConnectionsubclasseslist, so all list methods, including iteration, is available.TemplatingTemplateTemplate(subject=None,html=None,text=None,attachments=None,defaults=None)A templated e-mail.By default, the Template uses Python'sTemplaterenderer, which allows simple PHP-style substitution,
but this can be overridden using set_renderer().First, a template is defined:frommailemimportAttachmentfrommailem.templateimportTemplatesignup=Template('Congrats $user, you'vesignedup!','Welcome to our website!<br><img src="cid:logo.jpg" /> -- $domain',attachments=[Attachment('logo.jpg',open('logo.jpg').read(),'inline'))],defaults={'domain':'localhost'}# default template values)Now, having the template, you render it to aMessageby calling it:message=signup(['user@gmail.com'],dict(user='Honored User',))Ready for sending! :)subject: Message subject templatehtml: HTML message template, if anytext: Text message template, if anyattachments: Attachments for the template. Most probably, inline elements.defaults: Default template values, if required. The user can override these later.Template.set_rendererset_renderer(Renderer,**kwargs)Set renderer to be used with this template.A Renderer is any class that can be constructed with a template string argument,
and called with template values dict to render it.When no renderer was explicitly set, it defaults to PythonTemplateRenderer.Seemailem/template/renderer.py: it's easy to implement renderers with custom behavior!Renderer: Renderer class.**kwargs: Additional arguments to renderer, if supportedTemplate.defaultsdefaults(values)Set default values.New values will overwrite the previous.values: Default template valuesTemplate.call__call__(recipients,values,**kwargs)Create aMessageobject using the template values.recipients: Message recipients listvalues: Dictionary with template values**kwargs: keyword arguments for theMessageconstructorReturns:MessageThe renderedMessageobjectTemplate.from_directoryfrom_directory(path,subject_name='subject.txt',html_name='index.htm',text_name='index.txt',inline_rex='^i-(.*)')Convenience class method to import a directory as a template:subject.txtis the subject string templateindex.htmis the HTML templateindex.txtis the plaintext templateAll files matching the 'i-(*)' format are attached as 'inline', and hence can be referenced in the template:E.g. file 'i-flower.jpg' can be inlined as<img src="cid:flower.jpg" />.All other files are just attachments.Example:signup=Template.from_directory('templates/signup/')path: Path to the directorysubject_name: Subject template filenamehtml_name: Html template filenametext_name: Plaintext template filenameinline_rex: Regular expression to match files that should be inlined.If the RegExp defines capture groups, group $1 will be used as the fact filename.Returns:TemplateTemplateTemplateRegistryTemplateRegistry()E-Mail template registry.Simply contains all your templates and allows to render these by name.
Useful if you have multiple templates in your app and want to have them prepared.Initially, the registry is empty, and you addTemplateobjects one by one:frommailem.templateimportTemplate,TemplateRegistrytemplates=TemplateRegistry()templates.add('signup',Template('Congrats $user, you'vesignedup!','Welcome to our website!<br> -- $domain',))templates.defaults(dict(domain='example.com'))# set defaults on all templatesAlternatively, you can useTemplateRegistry.from_directory()to load templates
from filesystem.Now, to render a template, youget()it by name:msg=templates.get('signup')(['user@gmail.com'],dict(user='Honored User',))TemplateRegistry.addadd(name,template)Register a templatetemplate: Template objectReturns:mailem.template.TemplateThe added template (in case you want to set something on it)TemplateRegistry.set_rendererset_renderer(renderer,**kwargs)Set renderer to be used with all templates.Can be called both before adding templates and after.renderer: Renderer class to use**kwargs: Additional arguments for the rendererTemplateRegistry.defaultsdefaults(values)Set default values on all templates.New values will overwrite the previous.Can be called both before adding templates and after.values: Default template valuesTemplateRegistry.getget(name)Get a Template by namename: Template nameReturns:mailem.template.TemplateTemplateRegistry.from_directoryfrom_directory(path,**kwargs)Convenience method to construct a template registry
with a directory where each template is in a subdirectorypath: Path to templates**kwargs: Arguments toTemplate.from_directory(), if requiredReturns:mailem.template.registry.TemplateRegistry