#!/usr/bin/python # -*- coding: utf-8 -*- # (c) 2015, Matt Makai # # This file is part of Ansible # # Ansible is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Ansible is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Ansible. If not, see . ANSIBLE_METADATA = {'status': ['preview'], 'supported_by': 'community', 'version': '1.0'} DOCUMENTATION = ''' --- version_added: "2.0" module: sendgrid short_description: Sends an email with the SendGrid API description: - "Sends an email with a SendGrid account through their API, not through the SMTP service." notes: - "This module is non-idempotent because it sends an email through the external API. It is idempotent only in the case that the module fails." - "Like the other notification modules, this one requires an external dependency to work. In this case, you'll need an active SendGrid account." - "In order to use api_key, cc, bcc, attachments, from_name, html_body, headers you must pip install sendgrid" - "since 2.2 username and password are not required if you supply an api_key" requirements: - sendgrid python library options: username: description: - username for logging into the SendGrid account. - Since 2.2 it is only required if api_key is not supplied. required: false default: null password: description: - password that corresponds to the username - Since 2.2 it is only required if api_key is not supplied. required: false default: null from_address: description: - the address in the "from" field for the email required: true to_addresses: description: - a list with one or more recipient email addresses required: true subject: description: - the desired subject for the email required: true api_key: description: - sendgrid API key to use instead of username/password version_added: 2.2 required: false default: null cc: description: - a list of email addresses to cc version_added: 2.2 required: false default: null bcc: description: - a list of email addresses to bcc version_added: 2.2 required: false default: null attachments: description: - a list of relative or explicit paths of files you want to attach (7MB limit as per SendGrid docs) version_added: 2.2 required: false default: null from_name: description: - the name you want to appear in the from field, i.e 'John Doe' version_added: 2.2 required: false default: null html_body: description: - whether the body is html content that should be rendered version_added: 2.2 required: false default: false headers: description: - a dict to pass on as headers version_added: 2.2 required: false default: null author: "Matt Makai (@makaimc)" ''' EXAMPLES = ''' # send an email to a single recipient that the deployment was successful - sendgrid: username: "{{ sendgrid_username }}" password: "{{ sendgrid_password }}" from_address: "ansible@mycompany.com" to_addresses: - "ops@mycompany.com" subject: "Deployment success." body: "The most recent Ansible deployment was successful." delegate_to: localhost # send an email to more than one recipient that the build failed - sendgrid username: "{{ sendgrid_username }}" password: "{{ sendgrid_password }}" from_address: "build@mycompany.com" to_addresses: - "ops@mycompany.com" - "devteam@mycompany.com" subject: "Build failure!." body: "Unable to pull source repository from Git server." delegate_to: localhost ''' # ======================================= # sendgrid module support methods # import urllib try: import sendgrid HAS_SENDGRID = True except ImportError: HAS_SENDGRID = False def post_sendgrid_api(module, username, password, from_address, to_addresses, subject, body, api_key=None, cc=None, bcc=None, attachments=None, html_body=False, from_name=None, headers=None): if not HAS_SENDGRID: SENDGRID_URI = "https://api.sendgrid.com/api/mail.send.json" AGENT = "Ansible" data = {'api_user': username, 'api_key':password, 'from':from_address, 'subject': subject, 'text': body} encoded_data = urllib.urlencode(data) to_addresses_api = '' for recipient in to_addresses: if isinstance(recipient, unicode): recipient = recipient.encode('utf-8') to_addresses_api += '&to[]=%s' % recipient encoded_data += to_addresses_api headers = { 'User-Agent': AGENT, 'Content-type': 'application/x-www-form-urlencoded', 'Accept': 'application/json'} return fetch_url(module, SENDGRID_URI, data=encoded_data, headers=headers, method='POST') else: if api_key: sg = sendgrid.SendGridClient(api_key) else: sg = sendgrid.SendGridClient(username, password) message = sendgrid.Mail() message.set_subject(subject) for recip in to_addresses: message.add_to(recip) if cc: for recip in cc: message.add_cc(recip) if bcc: for recip in bcc: message.add_bcc(recip) if headers: message.set_headers(headers) if attachments: for f in attachments: name = os.path.basename(f) message.add_attachment(name, f) if from_name: message.set_from('%s <%s.' % (from_name, from_address)) else: message.set_from(from_address) if html_body: message.set_html(body) else: message.set_text(body) return sg.send(message) # ======================================= # Main # def main(): module = AnsibleModule( argument_spec=dict( username=dict(required=False), password=dict(required=False, no_log=True), api_key=dict(required=False, no_log=True), bcc=dict(required=False, type='list'), cc=dict(required=False, type='list'), headers=dict(required=False, type='dict'), from_address=dict(required=True), from_name=dict(required=False), to_addresses=dict(required=True, type='list'), subject=dict(required=True), body=dict(required=True), html_body=dict(required=False, default=False, type='bool'), attachments=dict(required=False, type='list') ), supports_check_mode=True, mutually_exclusive = [ ['api_key', 'password'], ['api_key', 'username'] ], required_together = [['username', 'password']], ) username = module.params['username'] password = module.params['password'] api_key = module.params['api_key'] bcc = module.params['bcc'] cc = module.params['cc'] headers = module.params['headers'] from_name = module.params['from_name'] from_address = module.params['from_address'] to_addresses = module.params['to_addresses'] subject = module.params['subject'] body = module.params['body'] html_body = module.params['html_body'] attachments = module.params['attachments'] sendgrid_lib_args = [api_key, bcc, cc, headers, from_name, html_body, attachments] if any(lib_arg != None for lib_arg in sendgrid_lib_args) and not HAS_SENDGRID: module.fail_json(msg='You must install the sendgrid python library if you want to use any of the following arguments: api_key, bcc, cc, headers, from_name, html_body, attachments') response, info = post_sendgrid_api(module, username, password, from_address, to_addresses, subject, body, attachments=attachments, bcc=bcc, cc=cc, headers=headers, html_body=html_body, api_key=api_key) if not HAS_SENDGRID: if info['status'] != 200: module.fail_json(msg="unable to send email through SendGrid API: %s" % info['msg']) else: if response != 200: module.fail_json(msg="unable to send email through SendGrid API: %s" % info['message']) module.exit_json(msg=subject, changed=False) # import module snippets from ansible.module_utils.basic import * from ansible.module_utils.urls import * if __name__ == '__main__': main()