def send_single_email(user, email, subject, title, message): message = escape(message) message = message.replace("~br~", "<br>") email_vars = {"preheader": "", "title": title, "message": message} email_string = render_to_string('email_without_button.html', {'email': email_vars}) if "SENDGRID_API_KEY" in os.environ: sg = sendgrid.SendGridAPIClient( apikey=os.environ.get('SENDGRID_API_KEY')) from_email = sendgrid.Email(settings.FROM_EMAIL) to_email = sendgrid.Email(email) subject = subject content = Content("text/html", email_string) mail = Mail(from_email, subject, to_email, content) response = sg.client.mail.send.post(request_body=mail.get()) if response.status_code == 202: log_user_event(user, "Sent email with subject: " + subject, "email", "Email content: " + message) return True else: return False log_user_event(user, "Failed to send email with subject: " + subject, "email", "Email content: " + message) raise RuntimeError("No SendGrid API key found in environment variables.")
def send_email(self, email: mail_.Email) -> bool: mail = sg_mail.Mail() personalization = sg_mail.Personalization() mail.set_from(sendgrid.Email(email.sender[1], email.sender[0])) mail.set_subject(email.subject) mail.add_content(sg_mail.Content("text/plain", email.content)) for recipient in email.recipients: personalization.add_to(sendgrid.Email(recipient)) if email.cc: for recipient in email.cc: personalization.add_cc(sendgrid.Email(recipient)) if email.bcc: for recipient in email.bcc: personalization.add_bcc(sendgrid.Email(recipient)) mail.add_personalization(personalization) response = self._sg_client.client.mail.send.post( request_body=mail.get()) if response.status_code in [202, 250]: return True elif response.status_code == 421: raise exceptions_.ServiceRateLimitException(self.name) elif response.status_code in [450, 550, 551, 552, 553]: exceptions_.InvalidRecipientException(self.name) else: exceptions_.GenericEmailServiceException(self.name) return False
def sendgrid_email(recipient, subject, msg): sg = sendgrid.SendGridAPIClient(apikey=SENDGRID_API_KEY) from_email = sendgrid.Email("*****@*****.**") to_email = sendgrid.Email(recipient) html_msg = "<p>%s</p>" % msg content = Content("text/html", html_msg) mail_to_send = Mail(from_email, subject, to_email, content) response = sg.client.mail.send.post(request_body=mail_to_send.get()) print "email nudge sent to user", response.status_code
def send_email(subject, to, template_name, context): sendgrid_client = sendgrid.SendGridAPIClient(apikey=settings.SENDGRID_API_KEY) from_email = sendgrid.Email(settings.DEFAULT_FROM_EMAIL) to_email = sendgrid.Email(to) content = Content("text/plain", render_to_string(template_name, context)) mail = Mail(from_email, subject, to_email, content) return sendgrid_client.client.mail.send.post(request_body=mail.get())
def send_email(email): sg = sendgrid.SendGridAPIClient(apikey=SENDGRIDAPI) from_email = sendgrid.Email("*****@*****.**") to_email = sendgrid.Email(email) subject = "Sending with SendGrid is Fun" content = sendgrid.Content("text/plain", "and easy to do anywhere, even with Python") mail = sendgrid.Mail(from_email, subject, to_email, content) response = sg.client.mail.send.post(request_body=mail.get()) print(response.status_code) print(response.body) print(response.headers)
def sendgrid_send_data_missing_email(msg, recipient): sg = sendgrid.SendGridAPIClient(apikey=SENDGRID_API_KEY) from_email = sendgrid.Email("*****@*****.**") to_email = sendgrid.Email(recipient) subject = "Beehive: Rescuetime data missing notification" logo_path = './static/images/beehive.png' content = Content("text/html", "<p>Hi,</p>" + "<p>Beehive has detected some rescuetime data issues. " \ + msg + " Please login to the rescuetime dashboard to see details. </p>" \ " <p> Dashboard: https://slm.smalldata.io/rescuetime/stats?days=7" + "</p>" \ "<br> <p> The Beehive team </p>") mail_to_send = Mail(from_email, subject, to_email, content) response = sg.client.mail.send.post(request_body=mail_to_send.get()) print "store_rescuetime_data: sendgrid email response code,",response.status_code
def send(self): sg = sendgrid.SendGridAPIClient(api_key=self.context.sendgrid_api_key) markdowner = Markdown(extras=["tables"]) from_email = sendgrid.Email(self.context.from_email) body = [] for a in self.analyses: stale_days = (datetime.datetime.now(tz=a.last_change.tzinfo) - a.last_change).days if a.last_change else "Never updated" body.append(line_item_template.format(file_path=a.doc_name, file_link=a.file_link, changed_by=a.changed_by_email, stale_days=stale_days)) plain_text = body_template.format(item_list="\n".join(body), github_repo=self.context.github_repo, github_repo_root=self.context.github_repo_path, max_stale_days=self.context.doc_is_stale_after_days) html_text = markdowner.convert(plain_text) content_text = sendgrid.Content("text/plain", plain_text) content_html = sendgrid.Content("text/html", html_text + "\n" + css) recipients = list(map(lambda x: sendgrid.To(x), self.recipients)) mail = sendgrid.Mail(from_email, recipients, self.subject(), plain_text_content=content_text, html_content=content_html) response = sg.client.mail.send.post(request_body=mail.get()) if 300 > response.status_code >= 200: success(f"Successfully sent email to {', '.join(self.recipients)} regarding {len(self.analyses)} files", 2) else: error( f"Failed to send email to {', '.join(self.recipients)} regarding {len(self.analyses)} files: " f"{response.status_code} - {response.body}", 2)
def send_templated_notification_simple(email, template_id, group_id, category): """ Send an email based on a template. :param str email: The email recipient :param str template_id: The template ID of the email. :param str template_id: The group ID of the email. pass to the email template. """ mail = sendgrid.helpers.mail.Mail() mail.from_email = sendgrid.Email("*****@*****.**", "Halite Challenge") personalization = sendgrid.helpers.mail.Personalization() personalization.add_to(sendgrid.helpers.mail.Email(email, email)) mail.add_personalization(personalization) mail.template_id = template_id mail.asm = sendgrid.helpers.mail.ASM(group_id, [ config.GOODNEWS_ACCOMPLISHMENTS, config.GAME_ERROR_MESSAGES, config.RESEARCH_EMAILS, config.NEWSLETTERS_ARTICLES ]) mail.add_category(sendgrid.helpers.mail.Category(category)) settings = sendgrid.helpers.mail.MailSettings() settings.sandbox_mode = sendgrid.helpers.mail.SandBoxMode( config.SENDGRID_SANDBOX_MODE) mail.mail_settings = settings response = sg.client.mail.send.post(request_body=mail.get()) print(response.status_code)
def email_profile_to(self, to_email): causes = self.causes.all() causes_string = "none :(" if causes.count() == 3: causes_string = "{}, {} and {}".format(causes[0], causes[1], causes[2]) elif causes.count() == 2: causes_string = "{} and {}".format(causes[0], causes[1]) elif causes.count() == 1: causes_string = causes[0] message = "{} has just signed up. Their membership level is {} and their selected causes are {}. " \ "Their email is {}.".format(self.get_full_name(), self.member_type, causes_string, self.user.email) email_vars = { "preheader": "", "title": "New member signup", "message": message } email_string = render_to_string('email_without_button.html', {'email': email_vars}) subject = "A new member signed up! ({})".format(self.get_full_name()) if "SENDGRID_API_KEY" in os.environ: sg = sendgrid.SendGridAPIClient( apikey=os.environ.get('SENDGRID_API_KEY')) from_email = sendgrid.Email(settings.FROM_EMAIL) to_email = sendgrid.Email(to_email) content = Content("text/html", email_string) mail = Mail(from_email, subject, to_email, content) response = sg.client.mail.send.post(request_body=mail.get()) if response.status_code == 202: log_user_event(self.user, "Sent email with subject: " + subject, "email", "Email content: " + email_string) return True log_user_event(self.user, "Failed to send email with subject: " + subject, "email", "Email content: " + email_string) return False
def __send_email(self, subject, body): if "SENDGRID_API_KEY" in os.environ: sg = sendgrid.SendGridAPIClient( apikey=os.environ.get('SENDGRID_API_KEY')) from_email = sendgrid.Email(settings.FROM_EMAIL) to_email = sendgrid.Email(self.email) subject = subject content = Content("text/html", body) mail = Mail(from_email, subject, to_email, content) response = sg.client.mail.send.post(request_body=mail.get()) if response.status_code == 202: log_user_event(self, "Sent email with subject: " + subject, "email", "Email content: " + body) return True log_user_event(self, "Failed to send email with subject: " + subject, "email", "Email content: " + body) raise RuntimeError( "No SendGrid API key found in environment variables.")
async def mailviasendgrid(message_str): mylog(u"mailing via sendgrid") sg_username = config.SENDGRID_USERNAME sg_recipient = config.SENDGRID_RECIPIENT sg_apikey = config.SENDGRID_APIKEY sg_client = sendgrid.SendGridAPIClient(sg_apikey) sg_from = sendgrid.Email(email=sg_username, name="IP Address Checker") message = sendgrid.Mail(from_email=sg_from, to_emails=[sg_recipient], subject=u"Update of IP Address", plain_text_content=message_str) message.reply_to = sg_recipient sg_client.send(message)
def send_email(receivers, subject, content, template_id=None, text_replacements=None, sender_name=None, sender_email=None, attachments=None, cc_list=None, bcc_list=None): print(os.environ.get('SENDGRID_API_KEY'), ' is the sendgrid api key') sendgrid_client = sendgrid.SendGridAPIClient( api_key=os.environ.get('SENDGRID_API_KEY')) sender = sendgrid.Email(name=sender_name, email=sender_email) mail = Mail(from_email=sender, subject=subject, content=content) personalization = Personalization() if len(receivers) == 0: error = Error({'detail': 'Please enter receiver mailId'}, status=status.HTTP_400_BAD_REQUEST) return error, None else: for receiver in receivers: personalization.add_to(receiver) personalization.add_to(receivers[0]) for cc in cc_list and cc_list is not None: personalization.add_cc(cc) for bcc in bcc_list and bcc_list is not None: personalization.add_bcc(bcc) mail.add_personalization(personalization) if text_replacements is not None: for text_replacement in text_replacements: for key, value in text_replacement.items(): mail.personalizations[0].add_substitution( Substitution(key, value)) mail.template_id = template_id if attachments is not None: for attachment in attachments: mail.add_attachment(attachment) response = sendgrid_client.client.mail.send.post( request_body=mail.get()) return {'status': True, 'response': response.body.decode().strip()}
def send_mail(message_str, subject, attach_html=None): sys.stderr.write("[info] mailing via sendgrid\n") sg_from = os.environ["SENDGRID_FROM"] sg_recipient = os.environ["SENDGRID_RECIPIENT"] sg_apikey = os.environ["SENDGRID_API_KEY"] sg_client = sendgrid.SendGridAPIClient(sg_apikey) sg_from = sendgrid.Email(name="Check Kindle Price", email=sg_from) message = sendgrid.Mail(from_email=sg_from, to_emails=[sg_recipient], subject=subject, html_content=message_str) message.reply_to = sg_recipient if attach_html: attachment_file = sendgrid.Attachment( file_content=base64.b64encode(attach_html).decode(), file_type="text/html", file_name="attach.html") message.add_attachment(attachment_file) sg_client.send(message)
def send_templated_notification(recipient, template_id, substitutions, group_id, category): """ Send an email based on a template. :param Recipient recipient: The recipient of the email :param str template_id: The template ID of the email. :param Dict[str, Any] substitutions: Any other substitution variables to :param str group_id: The group ID of the email. pass to the email template. """ mail = sendgrid.helpers.mail.Mail() if not recipient.organization: recipient = recipient._replace(organization="(no affiliation)") mail.from_email = sendgrid.Email("*****@*****.**", "Halite Challenge") personalization = sendgrid.helpers.mail.Personalization() personalization.add_to( sendgrid.helpers.mail.Email(recipient.email, recipient.username)) all_substitutions = itertools.chain(recipient._asdict().items(), substitutions.items()) for substitution_key, substitution_value in all_substitutions: personalization.add_substitution( sendgrid.helpers.mail.Substitution("-{}-".format(substitution_key), substitution_value)) mail.add_personalization(personalization) mail.template_id = template_id mail.asm = sendgrid.helpers.mail.ASM(group_id, [ config.GOODNEWS_ACCOMPLISHMENTS, config.GAME_ERROR_MESSAGES, config.RESEARCH_EMAILS, config.NEWSLETTERS_ARTICLES ]) mail.add_category(sendgrid.helpers.mail.Category(category)) settings = sendgrid.helpers.mail.MailSettings() settings.sandbox_mode = sendgrid.helpers.mail.SandBoxMode( config.SENDGRID_SANDBOX_MODE) mail.mail_settings = settings response = sg.client.mail.send.post(request_body=mail.get()) print(response.status_code)
def send_notification(recipient_email, recipient_name, subject, body, attachments=None): mail = sendgrid.helpers.mail.Mail() mail.from_email = sendgrid.Email("*****@*****.**", "Halite Challenge") personalization = sendgrid.helpers.mail.Personalization() personalization.add_to(sendgrid.helpers.mail.Email(recipient_email, recipient_name)) personalization.subject = "Halite Challenge: " + subject mail.add_personalization(personalization) mail.add_content(sendgrid.helpers.mail.Content("text/html", body)) settings = sendgrid.helpers.mail.MailSettings() settings.sandbox_mode = sendgrid.helpers.mail.SandBoxMode(config.SENDGRID_SANDBOX_MODE) mail.mail_settings = settings try: response = sg.client.mail.send.post(request_body=mail.get()) except HTTPError as e: app.logger.error("Could not send email", exc_info=e) app.logger.error("Response: {}".format(e.body))
def send_notification(recipient_email, recipient_name, subject, body, attachments=None): mail = sendgrid.helpers.mail.Mail() mail.from_email = sendgrid.Email("*****@*****.**", "Halite Challenge") personalization = sendgrid.helpers.mail.Personalization() personalization.add_to( sendgrid.helpers.mail.Email(recipient_email, recipient_name)) personalization.subject = "Halite Challenge: " + subject mail.add_personalization(personalization) mail.add_content(sendgrid.helpers.mail.Content("text/html", body)) settings = sendgrid.helpers.mail.MailSettings() settings.sandbox_mode = sendgrid.helpers.mail.SandBoxMode( config.SENDGRID_SANDBOX_MODE) mail.mail_settings = settings response = sg.client.mail.send.post(request_body=mail.get())
def overdue_cron(request): if "XERO_CONSUMER_KEY" in os.environ: with open(xero_rsa) as keyfile: rsa_key = keyfile.read() credentials = PrivateCredentials( os.environ.get('XERO_CONSUMER_KEY', "/usr/src/data/xerkey.pem"), rsa_key) xero = Xero(credentials) # Monkey patch the library to support pagination. def get_contacts(page): uri = '/'.join([ xero.contacts.base_url, xero.contacts.name, "?page=" + str(page) ]) params = {'summarizeErrors': False} return uri, params, 'get', None, None, False xero.contacts.get_contacts = xero.contacts._get_data(get_contacts) contacts = list() page = 0 while True: page += 1 result = xero.contacts.get_contacts(page) contacts += result if not result: break profiles = Profile.objects.all() deactivated_members = list() activated_members = list() for contact in contacts: if contact.get('IsCustomer', False) and contact.get( 'ContactStatus', False) == "ACTIVE": contact_id = contact['ContactID'] try: profile = profiles.get(xero_account_id=contact_id) if contact.get("Balances", False): print(contact["Balances"]["AccountsReceivable"] ["Outstanding"]) if contact["Balances"]["AccountsReceivable"][ "Outstanding"] > 0: if profile.state == "active": profile.deactivate() deactivated_members.append( profile.get_full_name()) else: if profile.state == "inactive": profile.activate() activated_members.append( profile.get_full_name()) else: if profile.state == "inactive": profile.activate() activated_members.append(profile.get_full_name()) except ObjectDoesNotExist: pass if "SENDGRID_API_KEY" in os.environ and len( deactivated_members) or len(activated_members): body = "HSBNE overdue fees check ran with {} overdue. These people have been deactivated:<br>{}<br><br>" \ "These people have been reactivated:<br>{}".format(len(deactivated_members), deactivated_members, activated_members) sg = sendgrid.SendGridAPIClient( apikey=os.environ.get('SENDGRID_API_KEY')) from_email = sendgrid.Email(settings.FROM_EMAIL_TREASURER) to_email = sendgrid.Email(settings.SYSADMIN_EMAIL) subject = "HSBNE overdue fees check ran with {} overdue and {} reactivated.".format( len(deactivated_members), len(activated_members)) content = sendgrid.helpers.mail.Content("text/html", body) mail = sendgrid.helpers.mail.Mail(from_email, subject, to_email, content) sg.client.mail.send.post(request_body=mail.get()) return HttpResponse(str(page) + "," + str(len(contacts))) else: return "Error checking overdue fees in Xero. No Xero API details."
def send_via_sendgrid(self, transport, mail, embedded_images, config): api_key = None if 'apiKey' in transport: api_key = transport['apiKey'] if os.getenv('SENDGRID_API_KEY'): api_key = os.getenv('SENDGRID_API_KEY') if not api_key: raise NotConfiguredException('No Sendgrid API key configured!') sg = sendgrid.SendGridAPIClient(api_key=api_key) from_email = sendgrid.Email(mail['mail_from']) to_email = sendgrid.To(mail['mail_to']) text_content = None if mail['text_body'] != '': text_content = sendgrid.Content('text/plain', mail['text_body']) sendgrid_mail = sendgrid.Mail(from_email, to_email, mail['mail_subject'], text_content) if mail['html_body'] != '': html_content = sendgrid.Content('text/html', mail['html_body']) sendgrid_mail.add_content(html_content) if len(embedded_images) > 0: for file_name, content in embedded_images.items(): attachment = Attachment() attachment.file_content = base64.b64encode(content).decode() attachment.file_type = 'application/octet-stream' attachment.file_name = file_name attachment.disposition = 'inline' attachment.content_id = file_name sendgrid_mail.attachment = attachment if 'attachments' in config['body']: for attachment in config['body']['attachments']: attachment_template = self.jinja_environment.from_string( attachment) attachment_template.name = 'attachment' attachment_url = attachment_template.render() self.logger.debug('Fetching attachment...', extra={'attachment': attachment_url}) filename, content = self._get_attachment(attachment_url) if filename: attachment = Attachment() attachment.file_content = base64.b64encode(content).decode() attachment.file_type = 'application/octet-stream' attachment.file_name = filename attachment.disposition = 'attachment' attachment.content_id = filename sendgrid_mail.attachment = attachment self.logger.debug('Attached file.', extra={ 'attachment_filename': filename, 'attachment_size': len(content) }) self.logger.debug('Sending email through SendGrid.') try: response = sg.client.mail.send.post( request_body=sendgrid_mail.get()) except exceptions.BadRequestsError as e: self.logger.error('Failed to send via SendGrid (bad request).', extra={'response': e.body}) raise e if response.status_code >= 200 and response.status_code <= 299: return True return False
if not keyword in entry.title: if not keyword in get_section(program_html, "番組概要"): if not keyword in get_section(program_html, "人名リンク"): if not keyword in get_section(program_html, "番組詳細"): sys.stderr.write( "[info] skipping %s (no matching keyword)\n" % entry.link) continue checked_thistime.append(url_num) mes = u"<a href=\"%s\">%s</a> (%s)" % ( entry.link, html.escape(entry.title), keyword) messages.append(mes) sess.close() if len(messages) > 0: message_str = "<br />\n".join(messages) sys.stderr.write(u"[info] mailing via sendgrid\n") sg_client = sendgrid.SendGridAPIClient(sg_apikey) sg_from = sendgrid.Email(name="Check TV Programs", email=sg_username) message = sendgrid.Mail(from_email=sg_from, to_emails=[sg_recipient], subject=u"Update of TV Programs", html_content=message_str) message.reply_to = sg_recipient sg_client.send(message) update_sheet(worksheet_checked_previously, checked_thistime)
def send_email(recipients: list, subject: str, text: str, html: str = '', sender: str = '', files: list = [], exceptions: bool = False): """ :param recipients: List of recipients; or single email (str); or comma-separated email list (str); or list of name-email pairs (e.g. settings.ADMINS) :param subject: Subject of the email :param text: Body (text) :param html: Body (html) :param sender: Sender email, or settings.DEFAULT_FROM_EMAIL if missing :param files: Paths to files to attach :param exceptions: Raise exception if email sending fails :return: Status code 202 if all emails were sent successfully, error status code otherwise """ import sendgrid from sendgrid.helpers.mail import Content, Mail, Attachment from django.conf import settings from base64 import b64encode from os.path import basename from django.utils.timezone import now from jutil.logs import log_event try: # default sender to settings.DEFAULT_FROM_EMAIL if not sender: sender = settings.DEFAULT_FROM_EMAIL # support multiple recipient list styles if isinstance( recipients, str): # allow single email and comma-separated list as input recipients = [str(r).strip() for r in recipients.split(',')] sg = sendgrid.SendGridAPIClient(apikey=settings.EMAIL_SENDGRID_API_KEY) from_email = sendgrid.Email(sender or settings.DEFAULT_FROM_EMAIL) content = Content('text/plain', text) if not html else Content( 'text/html', html) attachments = [] for filename in files: with open(filename, 'rb') as fp: attachment = Attachment() attachment.content = b64encode(fp.read()).decode() attachment.type = "application/octet-stream" attachment.filename = basename(filename) attachment.content_id = basename(filename) attachment.disposition = "attachment" attachments.append(attachment) except Exception as e: logger.error(e) if exceptions: raise return -1 status_codes = [] for recipient in recipients: try: t = now() to_email = sendgrid.Email() if isinstance(recipient, str): to_email.email = recipient elif (isinstance(recipient, list) or isinstance(recipient, tuple)) and len(recipient) == 2: to_email.name = recipient[0] to_email.email = recipient[1] else: raise Exception( 'Invalid recipient format: {}'.format(recipient)) mail = Mail(from_email=from_email, subject=subject, to_email=to_email, content=content) for attachment in attachments: mail.add_attachment(attachment) res = sg.client.mail.send.post(request_body=mail.get()) send_dt = (now() - t).total_seconds() if res.status_code == 202: log_event('EMAIL_SENT', data={ 'time': send_dt, 'to': recipient, 'subject': subject, 'status': res.status_code }) else: log_event('EMAIL_ERROR', data={ 'time': send_dt, 'to': recipient, 'subject': subject, 'status': res.status_code, 'body': res.body }) status_codes.append(res.status_code) except Exception as e: logger.error(e) if exceptions: raise status_codes.append(-1) for status in status_codes: if status != 202: return status return 202
def output(self): mail = { 'html_body': '', 'text_body': '', 'mail_from': '', 'mail_to': '', 'mail_subject': '', } if 'from' not in self.output_config: raise NotConfiguredException( 'No sender (from) configured for email output!') if 'to' not in self.output_config: raise NotConfiguredException( 'No recipient (to) configured for email output!') if 'subject' not in self.output_config: raise NotConfiguredException( 'No subject configured for email output!') if 'body' not in self.output_config: raise NotConfiguredException( 'No body configured for email output!') for mail_type in ['html', 'text']: if mail_type in self.output_config['body']: mail_template = self.jinja_environment.from_string( self.output_config['body'][mail_type]) mail_template.name = mail_type mail['%s_body' % mail_type] = mail_template.render() if mail['html_body'] == '' and mail['text_body'] == '': raise NotConfiguredException( 'No HMTL or text email body configured for email output!') for tpl in ['from', 'to', 'subject']: mail_template = self.jinja_environment.from_string( self.output_config[tpl]) mail['mail_%s' % tpl] = mail_template.render() self.logger.debug('Canonicalizing email formats...') # Canonicalize the email formats for tpl in ['from', 'to']: parsed_emails = email.utils.getaddresses([mail['mail_%s' % tpl]]) if tpl == 'from' and len(parsed_emails) > 1: raise MultipleSendersException( 'Multiple senders in from field!') new_email = '' for e in parsed_emails: new_email += ', ' if new_email != '' else '' new_email += email.utils.formataddr(e) mail['mail_%s' % tpl] = new_email if 'expandGroupRecipients' in self.output_config and self.output_config[ 'expandGroupRecipients']: to_emails = email.utils.getaddresses([mail['mail_to']]) self.logger.debug('Starting expansion of group recipients...', extra={'to': to_emails}) service_account = self.output_config[ 'serviceAccountEmail'] if 'serviceAccountEmail' in self.output_config else None user_credentials = Credentials( self.get_token_for_scopes([ 'https://www.googleapis.com/auth/admin.directory.user.readonly' ], service_account=service_account)) group_credentials = Credentials( self.get_token_for_scopes([ 'https://www.googleapis.com/auth/cloud-identity.groups.readonly' ], service_account=service_account)) user_service = discovery.build('admin', 'directory_v1', credentials=user_credentials) group_service = discovery.build('cloudidentity', 'v1beta1', credentials=group_credentials) new_emails = [] for e in to_emails: request = group_service.groups().lookup() request.uri += "&groupKey.id=" + e[1] try: response = request.execute() except errors.HttpError as exc: if exc.resp.status == 404 or exc.resp.status == 403: self.logger.debug( 'Did not find group %s in Cloud Identity.' % (e[1]), extra={'response': exc.resp}) response = None else: raise exc if response and 'name' in response: m_request = group_service.groups().memberships().list( parent=response['name']) m_response = m_request.execute() if 'memberships' in m_response: # If this field doesn't exist, it's probably an empty group for membership in m_response['memberships']: new_emails.append( email.utils.formataddr( ('', membership['memberKey']['id']))) else: try: u_response = user_service.users().get( userKey=e[1]).execute() if u_response: new_emails.append(e[1]) except errors.HttpError as exc: if not 'ignoreNonexistentGroups' in self.output_config or not self.output_config[ 'ignoreNonexistentGroups']: raise GroupNotFoundException( 'Failed to find group %s in Cloud Identity!' % e[1]) elif 'ignoreNonexistentGroups' in self.output_config and isinstance( self.output_config['ignoreNonexistentGroups'], str ) and not e[1].endswith( self.output_config['ignoreNonexistentGroups']): new_emails.append(e[1]) else: self.logger.debug('Non-existent user %s skipped.' % (e[1]), extra={'response': exc.resp}) new_to = '' for e in new_emails: new_to += ', ' if new_to != '' else '' new_to += e mail['mail_to'] = new_to self.logger.debug('Finished expanding group recipients.', extra={'to': new_to}) if 'transports' not in self.output_config: raise NotConfiguredException( 'No transports configured for sending email.') embedded_images = {} if 'images' in self.output_config['body']: for image in self.output_config['body']['images']: image_template = self.jinja_environment.from_string(image) image_template.name = 'image' image_url = image_template.render() self.logger.debug('Fetching attached image...', extra={'image': image_url}) image_filename = None if image_url.startswith('gs://'): # Cloud Storage file image_filename, image_content = self._get_attachment( image_url) else: if os.path.exists(image_url): # Local file image_filename = os.path.basename(image_url) image_content = open(image_url, 'rb').read() else: self.logger.error('Could not find image attachment.', extra={'image': image_url}) if image_filename: embedded_images[image_filename] = image_content self.logger.debug('Attaching embedded image.', extra={ 'image': image_url, 'image_name': image_filename, 'size': len(image_content) }) sent_successfully = False for transport in self.output_config['transports']: try: if transport['type'] == 'smtp': if 'host' not in transport: raise NotConfiguredException( 'No host configured for SMTP transport.') port = int( transport['port']) if 'port' in transport else 25 self.logger.debug('Trying transport.', extra={ 'host': transport['host'], 'port': port }) server = None if 'verifyCertificate' in transport and transport[ 'verifyCertificate'] == False: context = ssl._create_unverified_context() else: context = ssl.create_default_context() if 'ssl' in transport and transport['ssl']: self.logger.debug('Using SSL connection for SMTP.') server = smtplib.SMTP_SSL(transport['host'], port, context=context) else: server = smtplib.SMTP(transport['host'], port) if 'starttls' in transport and transport['starttls']: self.logger.debug('Using STARTTLS for SMTP.') server.starttls(context=context) if 'user' in transport and 'password' in transport: self.logger.debug('Logging into SMTP server.') server.login(transport['user'], transport['password']) message = MIMEMultipart('alternative') message['Subject'] = mail['mail_subject'] message['From'] = mail['mail_from'] message['To'] = mail['mail_to'] if mail['text_body'] != '': text_part = MIMEText(mail['text_body'], 'plain') message.attach(text_part) if mail['html_body'] != '': html_part = MIMEText(mail['html_body'], 'html') message.attach(html_part) if 'attachments' in self.output_config['body']: for attachment in self.output_config['body'][ 'attachments']: attachment_template = self.jinja_environment.from_string( attachment) attachment_template.name = 'attachment' attachment_url = attachment_template.render() self.logger.debug( 'Fetching attachment...', extra={'attachment': attachment_url}) filename, content = self._get_attachment( attachment_url) file_part = MIMEBase('application', 'octet-stream') file_part.set_payload(content) encoders.encode_base64(file_part) file_part.add_header( 'Content-Disposition', 'attachment; filename="%s"' % filename) self.logger.debug('Attached file.', extra={ 'attachment_filename': filename, 'attachment_size': len(content) }) message.attach(file_part) if len(embedded_images) > 0: for file_name, content in embedded_images.items(): image = MIMEImage(content) image.add_header('Content-ID', '<%s>' % file_name) image.add_header( 'Content-Disposition', 'inline; filename="%s"; size="%d";' % (file_name, len(content))) message.attach(image) self.logger.debug('Sending email thru SMTP.') server.sendmail(mail['mail_from'], mail['mail_to'], message.as_string()) server.quit() sent_successfully = True break elif transport['type'] == 'sendgrid': api_key = None if 'apiKey' in transport: api_key = transport['apiKey'] if os.getenv('SENDGRID_API_KEY'): api_key = os.getenv('SENDGRID_API_KEY') if not api_key: raise NotConfiguredException( 'No Sendgrid API key configured!') sg = sendgrid.SendGridAPIClient(api_key=api_key) from_email = sendgrid.Email(mail['mail_from']) to_email = sendgrid.To(mail['mail_to']) text_content = sendgrid.Content('text/plain', mail['text_body']) html_content = sendgrid.Content('text/html', mail['html_body']) sendgrid_mail = sendgrid.Mail(from_email, to_email, mail['mail_subject'], text_content) sendgrid_mail.add_content(html_content) if len(embedded_images) > 0: for file_name, content in embedded_images.items(): attachment = Attachment() attachment.file_content = base64.b64encode( content).decode() attachment.file_type = 'application/octet-stream' attachment.file_name = file_name attachment.disposition = 'inline' attachment.content_id = file_name sendgrid_mail.attachment = attachment if 'attachments' in self.output_config['body']: for attachment in self.output_config['body'][ 'attachments']: attachment_template = self.jinja_environment.from_string( attachment) attachment_template.name = 'attachment' attachment_url = attachment_template.render() self.logger.debug( 'Fetching attachment...', extra={'attachment': attachment_url}) filename, content = self._get_attachment( attachment_url) attachment = Attachment() attachment.file_content = base64.b64encode( content).decode() attachment.file_type = 'application/octet-stream' attachment.file_name = filename attachment.disposition = 'attachment' attachment.content_id = filename sendgrid_mail.attachment = attachment self.logger.debug('Attached file.', extra={ 'attachment_filename': filename, 'attachment_size': len(content) }) self.logger.debug('Sending email through SendGrid.') response = sg.client.mail.send.post( request_body=sendgrid_mail.get()) if response.status_code >= 200 and response.status_code <= 299: sent_successfully = True break else: self.logger.exception( 'Unknown transport type %s in configuration.' % transport['type']) except Exception: transport_sanitized = transport transport_sanitized.pop('apiKey', None) transport_sanitized.pop('user', None) transport_sanitized.pop('password', None) self.logger.exception( 'Error when attempting to use transport.', extra={ 'transport': transport_sanitized, 'mail': mail }) if not sent_successfully: self.logger.error( 'Unable to send email, none of the transports worked.') else: self.logger.info('Message sent!', extra={ 'from': mail['mail_from'], 'to': mail['mail_to'], 'subject': mail['mail_subject'] })
def invoice_cron(request): if "SENDGRID_API_KEY" in os.environ: pool = ThreadPool(100) def create_invoice(member): if member.profile.state == "active": if member.profile.last_invoice is not None: if member.profile.last_invoice.month == timezone.now( ).month: print("already invoiced this month") return { "name": member.profile.get_full_name(), "email": member.email, "success": False, "message": "User already invoiced this month." } elif member.profile.xero_account_id: return { "name": member.profile.get_full_name(), "email": member.email, "success": member.profile.create_membership_invoice(), "message": "" } elif member.profile.xero_account_id: return { "name": member.profile.get_full_name(), "email": member.email, "success": member.profile.create_membership_invoice(), "message": "" } return { "name": member.profile.get_full_name(), "email": member.email, "success": False, "message": "No contact in xero." } results = pool.map(create_invoice, User.objects.all()) successful = list() failed = list() successful_string, failed_string = "", "" for result in results: if result is not None: if result['success']: successful.append("{} - {}<br>".format( result['name'], result['email'])) successful_string += "{} - {} - {}<br>".format( result['name'], result['email'], result['message']) else: failed.append("{} - {} - {}<br>".format( result['name'], result['email'], result['message'])) failed_string += "{} - {} - {}<br>".format( result['name'], result['email'], result['message']) body = "HSBNE invoice generation ran with {} successful and {} failed.<br>".format(len(successful), len(failed)) + \ "Invoice creation for the following members failed: <br>{}<br><br>".format(failed_string) + \ "Invoice creation for the following members succeeded:<br>{}".format(successful_string) sg = sendgrid.SendGridAPIClient( apikey=os.environ.get('SENDGRID_API_KEY')) from_email = sendgrid.Email(settings.FROM_EMAIL_TREASURER) to_email = sendgrid.Email(settings.SYSADMIN_EMAIL) subject = "HSBNE invoice generation ran with {} successful and {} failed.".format( len(successful), len(failed)) content = sendgrid.helpers.mail.Content("text/html", body) mail = sendgrid.helpers.mail.Mail(from_email, subject, to_email, content) response = sg.client.mail.send.post(request_body=mail.get()) return HttpResponse(response.status_code)