Source code for astrobase.emailutils

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# emailutils.py - Waqas Bhatti (wbhatti@astro.princeton.edu) - Jun 2013
# License: MIT. See LICENSE.txt for complete text.

'''This is a small utility module to send email using an SMTP server that
requires logins. The email settings are stored in a file called .emailsettings
that should be located in the ~/.astrobase/ directory in your home
directory. This file should have permissions 0600 (so only you can read/write to
it), and should contain the following info in a single row, separated by the |
character::

        <email user>|<email password>|<email server>

Example::

        exampleuser@email.com|correcthorsebatterystaple|mail.example.com

NOTE: This assumes the email server uses STARTTLS encryption and listens on SMTP
port 587. Most email servers support this.

'''

from email.mime.text import MIMEText
from email.utils import formatdate, make_msgid
import smtplib
import socket

import os.path
import os
import stat

import time
from datetime import datetime

## EMAIL SETTINGS ##

# get config from the astrobase.conf file
import configparser

# parse the configuration file to get the default database credentials
CONF_FILE = os.path.abspath(os.path.expanduser('~/.astrobase/astrobase.conf'))

if not os.path.exists(CONF_FILE):
    # make the ~/.astrobase directory and copy over the astrobase.conf file to
    # it.
    import shutil

    # make the ~/.astrobase directory if it doesn't exist
    confpath = os.path.expanduser('~/.astrobase')
    if not os.path.exists(confpath):
        os.makedirs(confpath)
    modpath = os.path.dirname(os.path.abspath(__file__))

    # copy over the astrobase.conf file to ~/.astrobase if it doesn't exist
    if not os.path.exists(os.path.join(confpath,'astrobase.conf')):
        shutil.copy(os.path.join(modpath,'astrobase.conf'),
                    confpath)


CONF_FILE = os.path.abspath(
    os.path.expanduser('~/.astrobase/astrobase.conf')
)
CONF = configparser.ConfigParser()
CONF.read(CONF_FILE)

#
# Now, check the conf file for email credentials
#

# first, check if the .emailsettings file exists and has permissions 0600
SETTINGSFILE = os.path.join(os.path.expanduser('~/.astrobase'),
                            CONF.get('email','credentials'))

if os.path.exists(SETTINGSFILE):

    # check if this file is readable/writeable by user only
    fileperm = oct(os.stat(SETTINGSFILE)[stat.ST_MODE])

    # if we're good, read the settings
    if fileperm == '0100600' or fileperm == '0o100600':
        EMAIL_USER, EMAIL_PASSWORD, EMAIL_SERVER = open(
            SETTINGSFILE
        ).read().strip('\n').split('|')

    else:
        raise OSError('the email settings file %s has bad permissions '
                      '(you need to chmod 600 this file) and '
                      'is insecure, not reading...'
                      % SETTINGSFILE)
else:
    print('the email settings file: %s does not exist!' % SETTINGSFILE)
    EMAIL_USER, EMAIL_PASSWORD, EMAIL_SERVER = None, None, None

EMAIL_TEMPLATE = '''\
This is an automated notification from {sender} on {hostname}.

Time: {activity_time}

Report:

{activity_report}

'''


[docs]def send_email(sender, subject, content, email_recipient_list, email_address_list, email_user=None, email_pass=None, email_server=None): '''This sends an email to addresses, informing them about events. The email account settings are retrieved from the settings file as described above. Parameters ---------- sender : str The name of the sender to use in the email header. subject : str Subject of the email. content : str Content of the email. email_recipient list : list of str This is a list of email recipient names of the form: `['Example Person 1', 'Example Person 1', ...]` email_recipient list : list of str This is a list of email recipient addresses of the form: `['example1@example.com', 'example2@example.org', ...]` email_user : str The username of the email server account that will send the emails. If this is None, the value of EMAIL_USER from the ~/.astrobase/.emailsettings file will be used. If that is None as well, this function won't work. email_pass : str The password of the email server account that will send the emails. If this is None, the value of EMAIL_PASS from the ~/.astrobase/.emailsettings file will be used. If that is None as well, this function won't work. email_server : str The address of the email server that will send the emails. If this is None, the value of EMAIL_USER from the ~/.astrobase/.emailsettings file will be used. If that is None as well, this function won't work. Returns ------- bool True if email sending succeeded. False if email sending failed. ''' if not email_user: email_user = EMAIL_USER if not email_pass: email_pass = EMAIL_PASSWORD if not email_server: email_server = EMAIL_SERVER if not email_server and email_user and email_pass: raise ValueError("no email server address and " "credentials available, can't continue") msg_text = EMAIL_TEMPLATE.format( sender=sender, hostname=socket.gethostname(), activity_time='%sZ' % datetime.utcnow().isoformat(), activity_report=content ) email_sender = '%s <%s>' % (sender, EMAIL_USER) # put together the recipient and email lists email_recipients = [('%s <%s>' % (x,y)) for (x,y) in zip(email_recipient_list, email_address_list)] # put together the rest of the message email_msg = MIMEText(msg_text) email_msg['From'] = email_sender email_msg['To'] = ', '.join(email_recipients) email_msg['Message-Id'] = make_msgid() email_msg['Subject'] = '[%s on %s] %s' % ( sender, socket.gethostname(), subject ) email_msg['Date'] = formatdate(time.time()) # start the email process try: server = smtplib.SMTP(EMAIL_SERVER, 587) server.ehlo() if server.has_extn('STARTTLS'): try: server.starttls() server.ehlo() server.login(EMAIL_USER, EMAIL_PASSWORD) send_response = ( server.sendmail(email_sender, email_address_list, email_msg.as_string()) ) except Exception as e: print('script email sending failed with error: %s' % e) send_response = None if send_response is not None: print('script email sent successfully') server.quit() return True else: server.quit() return False else: print('email server does not support STARTTLS,' ' bailing out...') server.quit() return False except Exception as e: print('sending email failed with error: %s' % e) returnval = False server.quit() return returnval