Send email

The email service creates a service that can send email via SMTP. Here is a sample configuration for GMail:

email:
    gramex-guide-gmail:
        type: gmail                     # Type of email used is GMail
        email: gramex.guide@gmail.com   # Generic email ID used to test e-mails
        password: tlpmupxnhucitpte      # App-specific password created for Gramex guide

In the type: section of gramex.yaml email configuration, the following types are supported. You need to add your email: and password:.

You can also connect to any SMTP or SMTPS mail server using type: smtp or type: smtps. This includes:

For example:

email:
    amazon-ses:
        type: smtps
        host: email-smtp.eu-west-1.amazonaws.com    # AWS SES SMTP server for your region
        email: '***'                                # IAM access ID
        password: '***'                             # IAM password
    client-email:
        type: smtp              # Use type: smtps for SMTPS servers
        host: 10.20.30.40       # Host name or IP address of the SMTP server
        # Optional parameters
        email: user@domain.com  # Username or email to log into SMTP server
        password: '***'         # Password for SMTP server
        port: 587               # For non-standard SMTP port. Default: SMTPS=587, SMTP=25

Send email

This creates an SMTPMailer instance that can be used as follows:

from  gramex import service     # Available only if Gramex is running
mailer = service.email['gramex-guide-gmail']
# Or, to construct the SMTPMailer when using Gramex as a library, use:
# from gramex.services import SMTPMailer
# mailer = SMTPMailer(type='gmail', email='gramex.guide@gmail.com', password='...')
mailer.mail(
    to='person@example.com',
    subject='Subject',
    html='<strong>Bold text</strong>. <img src="cid:logo">'
    body='This plain text is shown if the client cannot render HTML',
    attachments=['1.pdf', '2.txt'],
    images={'logo': '/path/to/logo.png'})

The mail() method accepts the following arguments:

You can also pass any standard email header. Use small letters, replacing - with _. Here are some commonly used ones:

See the source in the example below to understand how to use it.

HTML email

Emails can have HTML content, text content, or both. HTML-friendly browsers like Outlook, GMail, etc display HTML content where available, and fall back to the text content.

The html= argument provides the HTML content. The body= argument provides the text content.

Writing HTML for email is quite different than for browsers. Here are some guides to read:

Email attachments

Attachments can be specified as filenames or as a dictionary with the body and content_type or filename keys. For example:

      attachments=['file.pdf']
      attachments=[{'filename': 'file.pdf', 'body': open('file.pdf', 'rb').read()}]
      attachments=[{'content_type': 'application/pdf', 'body': open('file.pdf', 'rb').read()}]

The attachment dict format is consistent with the handler.request.files structure that holds uploaded files.

Command-line emails

Gramex can be used as a standalone library to send emails as well. Here is a sample Python application:

from gramex.services import SMTPMailer

mailer = SMTPMailer(
    type='gmail',
    email='gramex.guide@gmail.com',       # Replace with your email ID
    password='tlpmupxnhucitpte',          # Replace with your passsword
)
mailer.mail(
    to='person@example.com',
    subject='Subject',
    html='<strong>This is bold text</strong> and <em>this is in italics</em>.'
    body='This plain text is shown if the client cannot render HTML',
    attachments=['1.pdf', '2.txt'])

The same parameters used in the gramex.yaml file may be used here.

Automated email alerts

Combined with schedule, you can automate email alerts. For example, this configuration sets up a schedule every weekday at 8am, and an email service.

schedule:
  email-alert:
    function: project.email_alert()     # Run this function
    hours: 8                            # at 8am on the system
    weekdays: mon,tue,wed,thu,fri       # every weekday

email:
  email-alert:                          # Define the email service to use
    type: smtp                          # Connect via SMTP
    host: mailserver.example.org        # to the mail server
    email: user@example.org             # with a login ID
    password: $MAIL_PASSWORD            # password stored in environment variable MAIL_PASSWORD

The project.email_alert() method can use this service to check if there are any unusual events, and send a templatized email if so. Here is a sample workflow for this:

def email_alert():
    data = gramex.cache.open(data_file, 'xlsx')                   # Open the data source
    analysis = find_unusual_events(data)                          # Apply some analysis
    if 'unusual' in analysis:                                     # If something is unusual
        tmpl = gramex.cache.open(template_file, 'template')       #   open a template
        service.email['email-alert'].mail(                        #   and send the email
            to='recipients@example.org',                          #   to the recipients
            subject='Alert: {unusual}'.format(**analysis),        #   with a clear subject
            html=tmpl.generate(data=data, analysis=analysis),     #   and render the template.
            attachments=[data_file],                              #   Maybe attach the data
        )

Test email service

To test an email service without sending an email, add stub: log to the configuration. For example:

email:
    email-test:
        type: gmail
        email: gramex.guide@gmail.com
        password: tlpmupxnhucitpte
        stub: log           # Don't send emails. Just print them to the console

When an email is sent via the email-test service above, it will not actually be sent. The email contents will be printed on the console.