def send_to_admin(serversmtp, frm, to, error, cur): logger.info('Send email about error to admin') # Get admin email address from database cur.execute("SELECT mb_value FROM `mb_properties` WHERE mb_field='Admin email'") admin = cur.fetchone()[0] # Create email fo admin msg = Message() msg.add_header('Subject', 'SRK DPIportal [Mail Sender] Impossible send email!') msg.add_header('Date', formatdate(localtime=True)) msg.add_header('X-Mailer', 'MailSender') msg.add_header('Message-ID', make_msgid()) msg.add_header('From', frm) msg.add_header('To', admin) msg.set_payload('Subject:' + msg['Subject'] + '\n' 'From:' + frm + '\n' 'To:' + admin + '\n\n' 'Impossible send email to ' + to + '\n' 'Error:\n' + error) try: serversmtp.sendmail(msg['From'], msg['To'].split('; '), msg.get_payload()) logger.info('Mail was send to %s' % admin) except Exception as e: logger.error(str(e)) logger.info('Impossible send email to admin %s' % admin)
def test_nested_series(self): """Handle a series sent in-reply-to an existing series.""" # create an old series with a "cover letter" msgids = [make_msgid()] project = create_project() series_v1 = create_series(project=project) create_series_reference(msgid=msgids[0], series=series_v1) # ...and three patches for i in range(3): msgids.append(make_msgid()) create_series_reference(msgid=msgids[-1], series=series_v1) # now create a new series with "cover letter" msgids.append(make_msgid()) series_v2 = create_series(project=project) ref_v2 = create_series_reference(msgid=msgids[-1], series=series_v2) # ...and the "first patch" of this new series msgid = make_msgid() email = self._create_email(msgid, msgids) series = find_series(project, email) # this should link to the second series - not the first self.assertEqual(len(msgids), 4 + 1) # old series + new cover self.assertEqual(series, ref_v2.series)
def reassemble_mail(self, parsed_email, to_keep, attachments): original_msgid = parsed_email.get_all('Message-ID') try: parsed_email.replace_header('Message-ID', make_msgid()) except: parsed_email.add_header('Message-ID', make_msgid()) if to_keep: if parsed_email.is_multipart(): parsed_email.set_payload([to_keep[0]]) else: parsed_email.set_payload(to_keep[0]) return parsed_email else: info_msg = MIMEText('Empty Message', _subtype='plain', _charset='utf-8') parsed_email.set_payload([info_msg]) for k in to_keep[1:]: parsed_email.attach(k) info = 'The attachments of this mail have been sanitzed.\nOriginal Message-ID: {}'.format(original_msgid) info_msg = MIMEText(info, _subtype='plain', _charset='utf-8') info_msg.add_header('Content-Disposition', 'attachment', filename='Sanitized.txt') parsed_email.attach(info_msg) for f in attachments: msg = self.pack_attachment(f) for m in msg: parsed_email.attach(m) return parsed_email
def test_first_reply(self): msgid_a = make_msgid() msgid_b = make_msgid() email = self._create_email(msgid_b, [msgid_a]) # assume msgid_a was already handled ref = create_series_reference(msgid=msgid_a) series = find_series(email) self.assertEqual(series, ref.series)
def send_mail(from_email, to_emails, subject, body, host='mail', port=25): """Send an email via SMTP @param from_email: email address for From: header @type from_email: str @param to_emails: sequence of email addresses for To: header @type to_email: [str] @param subject: text for Subject: header @type subject: unicode @param body: text for message body @type body: unicode @param host: mail server host @type host: str @param port: mail server port @type port: int """ connection = smtplib.SMTP(host, port) msg = MIMEText(body.encode('utf-8'), 'plain', 'utf-8') msg['Subject'] = subject.encode('utf-8') msg['From'] = from_email msg['To'] = ', '.join(to_emails) msg['Date'] = formatdate() msg['Message-ID'] = make_msgid() connection.sendmail(from_email, to_emails, msg.as_string()) connection.close()
def map_message(message, table): def container(message_id): return table.setdefault(message_id, Container()) w = Wrapper(message) this = container(w.message_id) # process case when we have two messages # with the same id, we should put # our current message to another container # otherwise the message would be lost if this.message: fake_id = make_msgid() this = container(fake_id) this.message = w # link message parents together prev = None for parent_id in w.references: parent = container(parent_id) if prev and not parent.parent and not introduces_loop(prev, parent): prev.add_child(parent) prev = parent # process case where this message has parent # unlink the old parent in this case if this.parent: this.parent.remove_child(this) # link to the cool parent instead if prev and not introduces_loop(prev, this): prev.add_child(this)
def generate_reply(self, message, result): try: from_mailaddr = '*****@*****.**' if message.get('Reply-To'): to = message.get('Reply-To') (to_realname,to_mailaddr) = email.utils.parseaddr(to) elif message.get('From'): to = message.get('From') (to_realname,to_mailaddr) = email.utils.parseaddr(to) msg = MIMEMultipart('encrypted', protocol='application/pgp-encrypted') msg['From'] = from_mailaddr msg['To'] = to msg['Subject'] = 'ud-mailgate processing results' msg['Message-Id'] = make_msgid() msg['In-Reply-To'] = message['Message-Id'] msg['Date'] = formatdate(localtime=True) msg['Content-Disposition'] = 'inline' part1 = MIMEApplication(_data='Version: 1\n', _subtype='pgp-encrypted', _encoder=encode_7or8bit) part1['Content-Disposition'] = 'attachment' msg.attach(part1) part2 = MIMEApplication(_data=result, _subtype='octet-stream', _encoder=encode_7or8bit) part2['Content-Disposition'] = 'inline; filename="msg.asc"' msg.attach(part2) fd = StringIO.StringIO() g = Generator(fd, mangle_from_=False) g.flatten(msg) if self.options['console']: self.stdout.write(fd.getvalue() + '\n') else: s = smtplib.SMTP('localhost') s.sendmail(from_mailaddr, to_mailaddr, fd.getvalue()) s.quit() except Exception as err: raise CommandError(err)
def __init__(self, subject=None, recipients=None, body=None, html=None, sender=None, cc=None, bcc=None, attachments=None, reply_to=None, date=None, charset=None, extra_headers=None, mail_options=None, rcpt_options=None): sender = sender if isinstance(sender, tuple): sender = formataddr(sender) self.recipients = recipients or [] self.subject = subject self.sender = sender or current_app.extensions['mail'].default_sender self.reply_to = reply_to self.cc = cc or [] self.bcc = bcc or [] self.body = body self.html = html self.date = date self.msgId = make_msgid() self.charset = charset self.extra_headers = extra_headers self.mail_options = mail_options or [] self.rcpt_options = rcpt_options or [] self.attachments = attachments or []
def setUp(self): mail = 'Message-Id: %s\n' % make_msgid() + \ 'From: %s\n' % self.sender + \ 'Subject: %s\n\n' % self.subject_header + \ 'test\n\n' + defaults.patch self.projects = defaults.project self.email = message_from_string(mail)
def doSendmail(server, subject, mailtext): """ This local function send the eMail @type server: SMTP @param server: An SMTP-Object that represents an open connection to an eMail-Server @type subject: string @param subject: Subject for the eMail @type mailtext: string @param mailtext: Mailtext for the eMail @return: nothing @exception: Exception if smtp.sendmail failed """ try: msg = MIMEText(mailtext, 'plain', 'UTF-8') msg['From'] = globalVars.config.get("eMail", "from") msg['To'] = globalVars.config.get("eMail", "to") msg['Subject'] = subject msg['Date'] = formatdate() msg['Message-Id'] = make_msgid() msg['Priority'] = globalVars.config.get("eMail", "priority") server.sendmail(globalVars.config.get("eMail", "from"), globalVars.config.get("eMail", "to").split(), msg.as_string()) except: logging.error("send eMail failed") logging.debug("send eMail failed", exc_info=True) raise
def flush(self,Nmin): res=[] with locker.lock('accumulating_notifcations'): for key in self.cache.keys(): (subject,sender,addressee)=key if self.cache[key]['N'] <= Nmin: ## flush only above a certain amount of messages continue destination = addressee.split(COMMASPACE) text = self.cache[key]['Text'] msg = MIMEMultipart() msg['From'] = sender msg['To'] = addressee msg['Date'] = formatdate(localtime=True) new_msg_ID = make_msgid() msg['Message-ID'] = new_msg_ID msg['Subject'] = subject ## add a signature automatically text += '\n\n' text += 'McM Announcing service' #self.logger.log('Sending a message from cache \n%s'% (text)) try: msg.attach(MIMEText(text)) smtpObj = smtplib.SMTP() smtpObj.connect() smtpObj.sendmail(sender, destination, msg.as_string()) smtpObj.quit() self.cache.pop(key) res.append( subject ) except Exception as e: print "Error: unable to send email", e.__class__ return res
def create_patch(**kwargs): """Create 'Patch' object.""" num = Patch.objects.count() # NOTE(stephenfin): Even though we could simply pass 'series' into the # constructor, we don't as that's not what we do in the parser and not what # our signal handlers (for events) expect series = kwargs.pop('series', None) number = kwargs.pop('number', None) values = { 'submitter': create_person() if 'submitter' not in kwargs else None, 'delegate': None, 'project': create_project() if 'project' not in kwargs else None, 'msgid': make_msgid(), 'state': create_state() if 'state' not in kwargs else None, 'name': 'testpatch%d' % num, 'headers': '', 'content': 'Patch testpatch%d' % num, 'diff': SAMPLE_DIFF, } values.update(kwargs) if 'patch_project' not in values: values['patch_project'] = values['project'] patch = Patch.objects.create(**values) if series: number = number or series.patches.count() + 1 series.add_patch(patch, number) return patch
def sendmail(to, subj, body, html=None, sender=None, cc=None, bcc=None, config={}): sendto = to msg = MIMEMultipart('alternative') msg.attach(MIMEText(body, 'plain')) if html: msg.attach(MIMEText(html, 'html')) msg['To'] = ','.join(to) msg['From'] = sender or config.get('from', '') msg['Subject'] = subj msg['Message-ID'] = make_msgid() msg['Date'] = formatdate() if cc is not None: msg['cc'] = ','.join(cc) sendto += cc if bcc is not None: msg['bcc'] = ','.join(bcc) sendto += bcc if config.get('ssl'): smtp_cls = SMTP_SSL else: smtp_cls = SMTP smtp = smtp_cls(host=config['host'], port=config['port']) smtp.ehlo() if config.get('tls'): smtp.starttls() smtp.login(user=config['username'], password=config['password']) smtp.sendmail(sender or config.get('from') or config.get('username'), sendto, msg.as_string()) smtp.close() yield
def send_message(self,message,subject=None): helo=self.configvars['helo'] if helo=='${myhostname}': helo=socket.gethostname() smtp=smtplib.SMTP(self.configvars['host'], int(self.configvars['port']), helo,20) if self.configvars['starttls'].lower().strip()=='yes': smtp.starttls() user=self.configvars['username'].strip() pw=self.configvars['password'].strip() if user!='' and pw!='': smtp.login(user,pw) c = message.encode(u'utf8', u'replace') txtattach = MIMEText(c, u'plain', u'utf8') outer = MIMEMultipart(u'alternative') outer[u'Subject'] = Header(subject).encode() outer[u'To'] = self.recipient outer[u'From'] = self.configvars['sender'] outer[u'auto-submitted'] = 'auto-generated' outer[u'Date'] = utils.formatdate(localtime=True) outer[u'Message-ID'] = utils.make_msgid() outer.attach(txtattach) smtp.sendmail(self.configvars['sender'], self.recipient, outer.as_string())
def createEmailTo(sender_name, sender_email, recipient_name, recipient_email, subject, body, format="plain"): """Create an :obj:`email.MIMEText.MIMEtext` instance for an email. This method will take care of adding addings a date header and message ID to the email, as well as quoting of non-ASCII content. """ if isinstance(body, unicode): mail=MIMEText(body.encode("utf-8"), format, "utf-8") else: mail=MIMEText(body, format) if sender_name: mail["From"]=emailutils.formataddr((sender_name, sender_email)) else: mail["From"]=sender_email if recipient_name: mail["To"]=emailutils.formataddr((recipient_name, recipient_email)) else: mail["To"]=recipient_email mail["Subject"]=Header(subject.encode("utf-8"), "utf-8") mail["Message-Id"]=emailutils.make_msgid() mail["Date"]=emailutils.formatdate(localtime=True) mail.set_param("charset", "utf-8") return mail
def __init__(self, sender, subject, recipients=None, body=None, html=None, cc=None, bcc=None, attachments=None, reply_to=None, date=None, charset=None, extra_headers=None): self.subject = subject self.sender = sender self.body = body self.html = html self.date = date self.msgId = make_msgid() self.charset = charset self.extra_headers = extra_headers self.cc = cc self.bcc = bcc self.reply_to = reply_to if recipients is None: recipients = [] self.recipients = list(recipients) if attachments is None: attachments = [] self.attachments = attachments
def get_root_message(self): """ Return the top level Message object which can be a standard Mime message or a Multi Part email. All the initial fields are set on the message. :return: email.Message object """ if (self.text and self.html) or self.attachments or self.embedded: self.message = MIMEMultipart('alternative', None) if self.text: self.message.attach(self.get_email_part(self.text, 'plain')) if self.html: self.message.attach(self.get_email_part(self.html, 'html')) elif self.text or self.html: if self.text: self.message = MIMEText(self.text.encode(self.charset), 'plain', self.charset) else: self.message = MIMEText(self.html.encode(self.charset), 'html', self.charset) else: self.message = MIMEText('', 'plain', 'us-ascii') self.message['From'] = self.format_email_address(email_type='from', emails=[self.sender]) if self.recipients: self.message['To'] = self.format_email_address(email_type='to', emails=self.recipients) if self.cc: self.message['Cc'] = self.format_email_address(email_type='cc', emails=self.recipients) self.message['Subject'] = self.get_header('subject', self.subject) self.message['Date'] = formatdate(localtime=True) # TODO check formatdate self.message['Message-ID'] = make_msgid(str(uuid.uuid4())) self.message['X-Mailer'] = 'Strudelpy Python Client' return self.message
def __init__( self, subject="", sender=None, to=None, cc=None, bcc=None, body=None, html=None, date=None, charset="utf-8", attachments=None, extra_headers=None, ): self.subject = subject self.sender = sender self.to = to or [] self.cc = cc or [] self.bcc = bcc or [] self.body = body self.html = html self.date = date self.messageID = make_msgid() self.charset = charset self.attachments = attachments or [] self.extra_headers = extra_headers or {}
def send_email(msg_to, msg_subject, msg_body, msg_from=None, smtp_server='localhost', envelope_from=None, headers={}): if not msg_from: msg_from = app.config['EMAIL_FROM'] if not envelope_from: envelope_from = parseaddr(msg_from)[1] msg = MIMEText(msg_body) msg['Subject'] = Header(msg_subject) msg['From'] = msg_from msg['To'] = msg_to msg['Date'] = formatdate() msg['Message-ID'] = make_msgid() msg['Errors-To'] = envelope_from if request: msg['X-Submission-IP'] = request.remote_addr s = smtplib.SMTP(smtp_server) s.sendmail(envelope_from, msg_to, msg.as_string()) s.close()
def __init__( self, ext, subject='', recipients=None, body=None, html=None, alts=None, sender=None, cc=None, bcc=None, attachments=None, reply_to=None, date=None, charset='utf-8', extra_headers=None, mail_options=None, rcpt_options=None ): sender = sender or ext.config.sender if isinstance(sender, tuple): sender = "%s <%s>" % sender self.ext = ext self.recipients = recipients or [] self.subject = subject self.sender = sender self.reply_to = reply_to self.cc = cc or [] self.bcc = bcc or [] self.body = body self.alts = dict(alts or {}) self.html = html self.date = date self.msgId = make_msgid() self.charset = charset self.extra_headers = extra_headers self.mail_options = mail_options or [] self.rcpt_options = rcpt_options or [] self.attachments = attachments or [] for attr in ['recipients', 'cc', 'bcc']: if not isinstance(getattr(self, attr), list): setattr(self, attr, [getattr(self, attr)])
def _create_email(msg, msgid=None, sender=None, listid=None): msg['Message-Id'] = msgid or make_msgid() msg['Subject'] = 'Test subject' msg['From'] = sender or 'Test Author <*****@*****.**>' msg['List-Id'] = listid or 'test.example.com' return msg
def send(self,message,rcpt=None): """ message : email.Message instance rcpt : List of recipients (normally parsed from To/Cc/Bcc fields) Send message """ # Check if connected and connect if false if not self.is_connected(): self.connect() # Extract recipients if rcpt is None: rcpt = [ addr[1] for addr in getaddresses((message.get_all('To') or []) + (message.get_all('Cc') or []) + (message.get_all('Bcc') or [])) ] # Fill in message fileds if not already set # NOTE: this modifies the original message and in particular deletes the Bcc field if message['From'] is None: message['From'] = self.sender if message['Reply-To'] is None: message['Reply-To'] = self.sender if message['Date'] is None: message['Date'] = formatdate(time.time(),localtime=True) if message['Message-ID'] is None: message['Message-ID'] = make_msgid() del message['Bcc'] # Send message self.session.sendmail(self.sender,rcpt,message.as_string())
def test_fetch(self): # Generate a fresh message-id each time because Gmail is # clever and will treat appends of messages with # previously seen message-ids as the same message. This # breaks our tests when the test message is updated. msg_id_header = make_msgid() msg = ('Message-ID: %s\r\n' % msg_id_header) + MULTIPART_MESSAGE self.client.select_folder(self.base_folder) self.client.append(self.base_folder, msg) fields = ['RFC822', 'FLAGS', 'INTERNALDATE', 'ENVELOPE'] msg_id = self.client.search()[0] resp = self.client.fetch(msg_id, fields) self.assertEqual(len(resp), 1) msginfo = resp[msg_id] self.assertSetEqual(set(msginfo.keys()), set(fields + ['SEQ'])) self.assertEqual(msginfo['SEQ'], 1) self.assertMultiLineEqual(msginfo['RFC822'], msg) self.assertIsInstance(msginfo['INTERNALDATE'], datetime) self.assertIsInstance(msginfo['FLAGS'], tuple) self.assertTupleEqual(msginfo['ENVELOPE'], ('Tue, 16 Mar 2010 16:45:32 +0000', 'A multipart message', (('Bob Smith', None, 'bob', 'smith.com'),), (('Bob Smith', None, 'bob', 'smith.com'),), (('Bob Smith', None, 'bob', 'smith.com'),), (('Some One', None, 'some', 'one.com'), (None, None, 'foo', 'foo.com')), None, None, None, msg_id_header))
def message(self): encoding = self.encoding or settings.DEFAULT_CHARSET msg = SafeMIMEText(self.body, self.content_subtype, encoding) msg = self._create_message(msg) msg['Subject'] = self.subject msg['From'] = self.extra_headers.get('From', self.from_email) self._set_list_header_if_not_empty(msg, 'To', self.to) self._set_list_header_if_not_empty(msg, 'Cc', self.cc) self._set_list_header_if_not_empty(msg, 'Reply-To', self.reply_to) # Email header names are case-insensitive (RFC 2045), so we have to # accommodate that when doing comparisons. header_names = [key.lower() for key in self.extra_headers] if 'date' not in header_names: # formatdate() uses stdlib methods to format the date, which use # the stdlib/OS concept of a timezone, however, Django sets the # TZ environment variable based on the TIME_ZONE setting which # will get picked up by formatdate(). msg['Date'] = formatdate(localtime=settings.EMAIL_USE_LOCALTIME) if 'message-id' not in header_names: # Use cached DNS_NAME for performance msg['Message-ID'] = make_msgid(domain=DNS_NAME) for name, value in self.extra_headers.items(): if name.lower() != 'from': # From is already handled msg[name] = value return msg
def __init__(self, subject, recipients=None, body=None, html=None, sender=None, cc=None, bcc=None, attachments=None, reply_to=None, date=None, charset=None, extra_headers=None): sender = sender or current_app.config.get("DEFAULT_MAIL_SENDER") if isinstance(sender, tuple): sender = "%s <%s>" % sender self.recipients = recipients or [] self.subject = subject self.sender = sender self.reply_to = reply_to self.cc = cc or [] self.bcc = bcc or [] self.body = body self.html = html self.date = date self.msgId = make_msgid() self.charset = charset self.extra_headers = extra_headers self.attachments = attachments or []
def test_new_series(self): msgid = make_msgid() email = self._create_email(msgid) project = create_project() self.assertIsNone(find_series(project, email, get_or_create_author(email)))
def create_email(content, subject=None, sender=None, multipart=False, project=None, content_encoding=None): if subject is None: subject = defaults.subject if sender is None: sender = defaults.sender if project is None: project = defaults.project project.save() if content_encoding is None: content_encoding = 'us-ascii' if multipart: msg = MIMEMultipart() body = MIMEText(content, _subtype='plain', _charset=content_encoding) msg.attach(body) else: msg = MIMEText(content, _charset=content_encoding) msg['Message-Id'] = make_msgid() msg['Subject'] = subject msg['From'] = sender msg['List-Id'] = project.listid return msg
def send_notification(to_address, subject, content_text, content_html, uid): msg = MIMEMultipart('alternative') plain = MIMEText(content_text, 'plain', _charset='utf-8') html = MIMEText(transform(content_html), 'html', _charset='utf-8') msg.attach(plain) msg.attach(html) msg['Subject'] = Header(SUBJECT_PREFIX + " " + subject, 'utf-8') msg['From'] = config.MAIL_FROM msg['To'] = to_address msg['Date'] = formatdate(time.time(), localtime=True) msg['Message-id'] = make_msgid() msg['X-LDAP-ID'] = uid logger.info("Mailing %s: '%s'", to_address, subject) logger.debug("Content: ---\n%s\n---", content_text) if config.NO_MAILS: logger.info("skipping mail, because config.NO_MAILS") return s = smtplib.SMTP(config.MAIL_HOST) s.connect(host=config.MAIL_HOST, port=config.MAIL_PORT) s.ehlo() s.starttls() s.login(user=config.MAIL_FROM, password=config.MAIL_PW) s.sendmail(config.MAIL_FROM, [to_address], msg.as_string()) s.quit()
def create_cover(**kwargs): """Create 'CoverLetter' object.""" num = CoverLetter.objects.count() # NOTE(stephenfin): Despite first appearances, passing 'series' to the # 'create' function doesn't actually cause the relationship to be created. # This is probably a bug in Django. However, it's convenient to do so we # emulate that here. For more info, see [1]. # # [1] https://stackoverflow.com/q/43119575/ series = kwargs.pop('series', None) values = { 'submitter': create_person() if 'person' not in kwargs else None, 'project': create_project() if 'project' not in kwargs else None, 'msgid': make_msgid(), 'name': 'testpatch%d' % num, 'headers': '', 'content': '', } values.update(kwargs) cover = CoverLetter.objects.create(**values) if series: series.add_cover_letter(cover) return cover
def _generate_mail_content(schedule, screenshot, name, url): if schedule.delivery_type == EmailDeliveryType.attachment: images = None data = { 'screenshot.png': screenshot, } body = __( '<b><a href="%(url)s">Explore in Superset</a></b><p></p>', name=name, url=url, ) elif schedule.delivery_type == EmailDeliveryType.inline: # Get the domain from the 'From' address .. # and make a message id without the < > in the ends domain = parseaddr(config.get('SMTP_MAIL_FROM'))[1].split('@')[1] msgid = make_msgid(domain)[1:-1] images = { msgid: screenshot, } data = None body = __( """ <b><a href="%(url)s">Explore in Superset</a></b><p></p> <img src="cid:%(msgid)s"> """, name=name, url=url, msgid=msgid, ) return EmailContent(body, data, images)
def send_msg(self, body, who, subject=None, **kwargs): """Sends email and SMS messages. **NOTES FOR TARGETING RECIPIENTS WITH 'who':** - `'who'` can be a user name, group name, email, or mobile number. - It can be an individual item or a list of items. - User and group names are defined in ``contact_list.json``. - When targeting users or groups, you can toggle the mode of communication using `use_email` and `use_sms`. By default, only SMS is used. - Mobile numbers can be any format, but they must contain 10 digits in addition to any leading 0s or 1s. Integers and strings are OK. Arguments: body (str): Contents of message. who (obj): User name, group name, email, or mobile number. Single items, or a list of many. See notes. subject (str): Optional. Subject of message. Default is None. Keyword Arguments: attachment (Path): Path-like object that points to a file. Default is None. disable_email (bool): If True, emails will not be sent to any recipients. This can be useful if you want to send only SMS messages to users or groups in the contact_list.json. Default is False. disable_sms (bool): If True, SMS messages will not be sent to any recipients. This can be useful if you want to send only email messages to users or groups in the contact_list.json. Default is False. Returns: No returns. """ # ============================================================ # Parse and bail out if needed # ============================================================ self._parse_who(who) if not self._ensure_recipients_exist(): return # Kwargs attachment = kwargs.get('attachment', None) disable_email = kwargs.get('disable_email', False) disable_sms = kwargs.get('disable_sms', False) if not self._ensure_attachment_exists(attachment): return for b, n in zip([disable_email, disable_sms], ['disable_email', 'disable_sms']): if not isinstance(b, bool): msg = f'\'{n}\' must be boolean but you gave type {type(b)}' raise TypeError(msg) # ============================================================ # Main # ============================================================ with self._setup_smtp_server() as sess: # Create msg object msg = EmailMessage() # Personalize the template body_from_template = self.template.substitute(BODY=body) # Set msg parameters; # Note we will assign msg['To'] below when iterating over email addresses msg['From'] = self.sender_address msg['Subject'] = subject.upper() if isinstance(subject, str) else None # Copy outgoing emails to cc list if isinstance(self.cc_email_list, list): if len(self.cc_email_list) > 0: msg['CC'] = ','.join(self.cc_email_list) # Base text message msg.set_content(body_from_template) # HTML version body_html = re.sub(r'[\n]', '<br>', body_from_template) # Replace /n with <br> logo_cid = make_msgid() msg.add_alternative("""\ <html> <head></head> <body> <p>""" + body_html + '</p>' + """ <a href="https://www.liveline.tech"> <img src="cid:{logo_cid}" /> </a> </body> </html> """.format(logo_cid=logo_cid[1:-1]), subtype='html') # Add logo to the HTML version if EMAIL_SIGNATURE_LOGO_FILE is not None: t = root / EMAIL_SIGNATURE_LOGO_FILE if t.exists(): with open(t, 'rb') as img: r = img.read() # noinspection PyUnresolvedReferences msg.get_payload()[1].add_related(r, 'image', 'png', cid=logo_cid) # Optionally attach a file # First use mimetypes to try and guess content type based on file extension: if attachment is not None: attachment = Path(attachment) ctype, encoding = mimetypes.guess_type(str(attachment)) if ctype is None or encoding is not None: # No guess could be made, or the file is encoded (compressed), so # use a generic bag-of-bits type. ctype = 'application/octet-stream' maintype, subtype = ctype.split('/', 1) maintype += f'; name="{attachment.name}"' with open(attachment, 'rb') as file: r = file.read() msg.add_attachment(r, maintype=maintype, subtype=subtype) # ============================================================ # Email # ============================================================ # For each email & phone in current lists, send messages if not disable_email: for e in self.current_email_list: # Console out stdout_msg = f'COMMUNICATOR MESSAGE: Sending email to: ' fancy_print(stdout_msg, fg=COMMUNICATOR_MSG_COLOR, end='') fancy_print(e, fg='hlink') # Update msg 'To:' field if msg['To'] is not None: del msg['To'] msg['To'] = e # # Make a local copy of what we are going to send... to a log file? # with open('outgoing.msg', 'wb') as f: # f.write(bytes(msg)) try: sess.send_message(msg) except: stdout_msg = f'COMMUNICATOR WARNING: Failed sending email message' fancy_print(stdout_msg, fg=COMMUNICATOR_WARN_COLOR) # ============================================================ # SMS # ============================================================ if not disable_sms: for m in self.current_mobile_list: # Console out stdout_msg = f'COMMUNICATOR MESSAGE: Sending SMS message to: ' fancy_print(stdout_msg, fg=COMMUNICATOR_MSG_COLOR, end='') fancy_print(m[0:3] + '.' + m[3:6] + '.' + m[6:10], fg='cerulean') any_ok = False candidates = list() # Try all the stubs! # We don't know the carrier name. # Assume the invalid addresses will get black-holed by the various carriers. for stub in self.sms_email_stubs: candidates.append(m + self.sms_email_stubs[stub]) # Update msg 'To:' field if msg['To'] is not None: del msg['To'] msg['To'] = candidates # # Make a local copy of what we are going to send... to a log file? # with open('outgoing.msg', 'wb') as f: # f.write(bytes(msg)) try: sess.send_message(msg) any_ok = True except: pass if not any_ok: stdout_msg = f'COMMUNICATOR WARNING: Failed sending SMS message' fancy_print(stdout_msg, fg=COMMUNICATOR_WARN_COLOR) return
# from email.MIMEMultipart import MIMEMultipart from email.mime.multipart import MIMEMultipart # from email import Encoders, Utils from email.utils import formatdate, make_msgid # mail['Date'] = Utils.formatdate(localtime=1) mail['Date'] = formatdate(localtime=1) # mail['Message-ID'] = Utils.make_msgid() mail['Message-ID'] = make_msgid() # s = smtplib.SMTP(smtp_server, smtp_port) s = smtplib.SMTP_SSL(smtp_server, smtp_port)
def build_email( self, email_from, email_to, subject, body, email_cc=None, email_bcc=None, reply_to=False, attachments=None, message_id=None, references=None, object_id=False, subtype="plain", headers=None, body_alternative=None, subtype_alternative="plain", ): """ copy-pasted from odoo/addons/base/models/ir_mail_server.py::build_email """ ftemplate = "__image-%s__" fcounter = 0 attachments = attachments or [] pattern = re.compile(r'"data:image/png;base64,[^"]*"') pos = 0 new_body = "" body = body or "" while True: match = pattern.search(body, pos) if not match: break s = match.start() e = match.end() data = body[s + len('"data:image/png;base64,'):e - 1] new_body += body[pos:s] fname = ftemplate % fcounter fcounter += 1 attachments.append((fname, base64.b64decode(data))) new_body += '"cid:%s"' % fname pos = e new_body += body[pos:] body = new_body email_from = email_from or tools.config.get("email_from") assert email_from, ( "You must either provide a sender address explicitly or configure " "a global sender address in the server configuration or with the " "--email-from startup parameter.") # Note: we must force all strings to to 8-bit utf-8 when crafting message, # or use encode_header() for headers, which does it automatically. headers = headers or {} # need valid dict later if not email_cc: email_cc = [] if not email_bcc: email_bcc = [] if not body: body = u"" email_body_utf8 = ustr(body).encode("utf-8") email_text_part = MIMEText(email_body_utf8, _subtype=subtype, _charset="utf-8") msg = MIMEMultipart() if not message_id: if object_id: message_id = tools.generate_tracking_message_id(object_id) else: message_id = make_msgid() msg["Message-Id"] = encode_header(message_id) if references: msg["references"] = encode_header(references) msg["Subject"] = encode_header(subject) msg["From"] = encode_rfc2822_address_header(email_from) del msg["Reply-To"] if reply_to: msg["Reply-To"] = encode_rfc2822_address_header(reply_to) else: msg["Reply-To"] = msg["From"] msg["To"] = encode_rfc2822_address_header(COMMASPACE.join(email_to)) if email_cc: msg["Cc"] = encode_rfc2822_address_header( COMMASPACE.join(email_cc)) if email_bcc: msg["Bcc"] = encode_rfc2822_address_header( COMMASPACE.join(email_bcc)) msg["Date"] = formatdate() # Custom headers may override normal headers or provide additional ones for key, value in headers.items(): msg[ustr(key).encode("utf-8")] = encode_header(value) if subtype == "html" and not body_alternative and html2text: # Always provide alternative text body ourselves if possible. text_utf8 = tools.html2text( email_body_utf8.decode("utf-8")).encode("utf-8") alternative_part = MIMEMultipart(_subtype="alternative") alternative_part.attach( MIMEText(text_utf8, _charset="utf-8", _subtype="plain")) alternative_part.attach(email_text_part) msg.attach(alternative_part) elif body_alternative: # Include both alternatives, as specified, within a multipart/alternative part alternative_part = MIMEMultipart(_subtype="alternative") body_alternative_utf8 = ustr(body_alternative).encode("utf-8") alternative_body_part = MIMEText(body_alternative_utf8, _subtype=subtype_alternative, _charset="utf-8") alternative_part.attach(alternative_body_part) alternative_part.attach(email_text_part) msg.attach(alternative_part) else: msg.attach(email_text_part) if attachments: for (fname, fcontent, mime) in attachments: filename_rfc2047 = encode_header_param(fname) if mime and "/" in mime: maintype, subtype = mime.split("/", 1) part = MIMEBase(maintype, subtype) else: part = MIMEBase("application", "octet-stream") # The default RFC2231 encoding of Message.add_header() works in Thunderbird but not GMail # so we fix it by using RFC2047 encoding for the filename instead. part.sudo().set_param("name", filename_rfc2047) part.add_header("Content-Disposition", "attachment", filename=filename_rfc2047) part.add_header("Content-ID", "<%s>" % filename_rfc2047) # NEW STUFF part.set_payload(fcontent) encoders.encode_base64(part) msg.attach(part) return msg
def sending_email(recipients, sender_name, sender_email, subject, body, body_txt, files, cclist, bcclist, email_server, dkim_private_path, dkim_selector): msg = MIMEMultipart() msg['Date'] = formatdate(localtime=True) msg['Subject'] = six.text_type(subject) msg['To'] = ", ".join(recipients) if isinstance(cclist, list): cclist = split_doubled_email(cclist) for recipient in recipients: if recipient in cclist: cclist.remove(recipient) msg['Cc'] = ", ".join(cclist) recipients.extend(cclist) if isinstance(bcclist, list): bcclist = split_doubled_email(bcclist) for recipient in recipients: if recipient in bcclist: bcclist.remove(recipient) recipients.extend(bcclist) domain = sender_email.split('@')[-1] msg_from = "%s <%s>" % (sender_name, sender_email) msg['From'] = msg_from msg['Organization'] = sender_name msg['Return-Path'] = sender_email msg['Reply-To'] = sender_email msg['Message-ID'] = make_msgid(domain=domain) body = six.text_type(body).strip() if body[:6].lower() == '<html>': if body_txt is None: h2txt = HTML2Text() h2txt.ignore_links = False h2txt.wrap_links = False body_txt = h2txt.handle(body) msg_alternative = MIMEMultipart('alternative') msg_alternative.attach(MIMEText(body, 'html', 'utf-8')) msg_alternative.attach(MIMEText(body_txt, 'plain', 'utf-8')) msg.attach(msg_alternative) else: msg.attach(MIMEText(body, 'plain', 'utf-8')) if (files is not None) and (len(files) > 0): for filename, file in files: msg.attach( MIMEApplication( file.read(), Content_Disposition='attachment; filename="%s"' % filename, Name=filename)) if (dkim_private_path != '') and isfile(dkim_private_path) and (dkim_selector != ''): import dkim with open(dkim_private_path) as dkim_private_file: privateKey = dkim_private_file.read() headers = [b'from', b'to', b'subject'] sig = dkim.sign(msg.as_string().encode(), dkim_selector.encode(), domain.encode(), privateKey.encode(), include_headers=headers) sig = sig.decode() msg['DKIM-Signature'] = sig[len("DKIM-Signature: "):] try: return email_server.sendmail(msg_from, recipients, msg.as_string()) except Exception as error: raise EmailException(six.text_type(error)) finally: if email_server: email_server.quit()
from email.utils import make_msgid server = smtplib.SMTP('smtp.gmail.com', 587) server.starttls() username = "" password = "" server.login(username, password) FROM = "*****@*****.**" #<from-address> TO = "*****@*****.**" #[<to-addres>] SUBJECT = "Hello!" TEXT = "This message was sent with Python's smtplib." message = 'Subject: {}\n\n{}'.format(SUBJECT, TEXT) message = EmailMessage() asparagus_cid = make_msgid() message['Subject'] = "This is a test msg" message['From'] = Address("Jimut", "Jimut", "*****@*****.**") message['To'] = (Address("Jimut B.", "Jimut1", "*****@*****.**"), Address("Jimut B. Pal", "Jimut", "*****@*****.**")) message.set_content("""\ Rse! Cela ressemble à un excellent recipie[1] déjeuner. [1] http://www.yummly.com/recipe/Roasted-Asparagus-Epicurious-203718 --Pepé """) message.add_alternative("""\ <html>
from email import utils, encoders import mimetypes, sys def alternative(data, contenttype): maintype, subtype = contenttype.split('/') if maintype == 'text': retival = MIMEText(data, _subtype=subtype) else: retival = MIMEBase(maintype, subtype) retival.set_payload(data) encoders.encode_base64(retival) return retival messagetext = """Hello, This is a *great* test message from chapter 9. I hope you enjoy it! -- Anonymous""" messagehtml = """Hello, <p> This is a <b>great</b> test message from Chapter 9. I hope you enjoy it!</p> -- <i>Anonymous</i>""" msg = MIMEMultipart('alternative') msg['TO'] = '*****@*****.**' msg['From'] = 'Test Sender <*****@*****.**>' msg['Subject'] = 'Test Message, Chapter 9' msg['Date'] = utils.formatdate(localtime=1) msg['Message-ID'] = utils.make_msgid() msg.attach(alternative(messagetext, 'text/plain')) msg.attach(alternative(messagehtml, 'text/html')) print(msg.as_bytes().decode())
def build_msg_html_image(*args): ''' 用户需要依次传入 subject, receiver, html, [ image | start_time, end_time, idc_name ] 等参数, 其他参数都是默认的,也可以在本函数中自行修改。 ''' # 解析参数 subject = args[0] receiver = args[1] html = args[2] if len(args) == 4: image = args[3] elif len(args) == 6: start_time = args[3] end_time = args[4] idc_name = args[5] else: print('invalid args, please check!') exit(2) ## 下面参数请根据实际需要修改 sender = '*****@*****.**' # cc = ['*****@*****.**'] # bcc = ['*****@*****.**'] msg = MIMEMultipart('alternative') msg['Subject'] = Header(subject, 'utf-8') msg['From'] = formataddr(['易网信Robot ', sender]) msg['To'] = ','.join(receiver) # 根据实际情况决定 抄送,暗送 # msg['Cc'] = ','.join(cc) # msg['Bcc'] = ','.join(bcc) msg['Message-id'] = make_msgid() msg['Date'] = formatdate(localtime=1) ## 下面参数请根据实际需要修改 image_logo = "image/logo.jpg" image_logo_id = 'image_logo_id' with open(image_logo, "rb") as f: logo = MIMEImage(f.read()) f.close() logo.add_header('Content-ID', image_logo_id) msg.attach(logo) ## 下面参数请根据实际需要修改 html_footer = 'html_footer.txt' f = open(html_footer, 'rb') html_footer = f.read().decode() % (image_logo_id) f.close() f = open(html, 'rb') if len(args) == 4: image_id = 'image_id' with open(image, "rb") as f2: new_year = MIMEImage(f2.read()) f2.close() new_year.add_header('Content-ID', image_id) msg.attach(new_year) html = f.read().decode() % (image_id, html_footer) elif len(args) == 6: html = f.read().decode() % (idc_name, start_time, end_time, html_footer) f.close() msg_html_image = MIMEText(html, 'html', 'utf-8') msg.attach(msg_html_image) return msg
def build_email(self, email_from, email_to, subject, body, email_cc=None, email_bcc=None, reply_to=False, attachments=None, message_id=None, references=None, object_id=False, subtype='plain', headers=None, body_alternative=None, subtype_alternative='plain'): """Constructs an RFC2822 email.message.Message object based on the keyword arguments passed, and returns it. :param string email_from: sender email address :param list email_to: list of recipient addresses (to be joined with commas) :param string subject: email subject (no pre-encoding/quoting necessary) :param string body: email body, of the type ``subtype`` (by default, plaintext). If html subtype is used, the message will be automatically converted to plaintext and wrapped in multipart/alternative, unless an explicit ``body_alternative`` version is passed. :param string body_alternative: optional alternative body, of the type specified in ``subtype_alternative`` :param string reply_to: optional value of Reply-To header :param string object_id: optional tracking identifier, to be included in the message-id for recognizing replies. Suggested format for object-id is "res_id-model", e.g. "12345-crm.lead". :param string subtype: optional mime subtype for the text body (usually 'plain' or 'html'), must match the format of the ``body`` parameter. Default is 'plain', making the content part of the mail "text/plain". :param string subtype_alternative: optional mime subtype of ``body_alternative`` (usually 'plain' or 'html'). Default is 'plain'. :param list attachments: list of (filename, filecontents) pairs, where filecontents is a string containing the bytes of the attachment :param list email_cc: optional list of string values for CC header (to be joined with commas) :param list email_bcc: optional list of string values for BCC header (to be joined with commas) :param dict headers: optional map of headers to set on the outgoing mail (may override the other headers, including Subject, Reply-To, Message-Id, etc.) :rtype: email.message.Message (usually MIMEMultipart) :return: the new RFC2822 email message """ email_from = email_from or self._get_default_from_address() assert email_from, "You must either provide a sender address explicitly or configure "\ "using the combintion of `mail.catchall.domain` and `mail.default.from` "\ "ICPs, in the server configuration file or with the "\ "--email-from startup parameter." # Note: we must force all strings to to 8-bit utf-8 when crafting message, # or use encode_header() for headers, which does it automatically. headers = headers or {} # need valid dict later email_cc = email_cc or [] email_bcc = email_bcc or [] body = body or u'' email_body = ustr(body) email_text_part = MIMEText(email_body, _subtype=subtype, _charset='utf-8') msg = MIMEMultipart() if not message_id: if object_id: message_id = tools.generate_tracking_message_id(object_id) else: message_id = make_msgid() msg['Message-Id'] = encode_header(message_id) if references: msg['references'] = encode_header(references) msg['Subject'] = encode_header(subject) msg['From'] = encode_rfc2822_address_header(email_from) del msg['Reply-To'] if reply_to: msg['Reply-To'] = encode_rfc2822_address_header(reply_to) else: msg['Reply-To'] = msg['From'] msg['To'] = encode_rfc2822_address_header(COMMASPACE.join(email_to)) if email_cc: msg['Cc'] = encode_rfc2822_address_header( COMMASPACE.join(email_cc)) if email_bcc: msg['Bcc'] = encode_rfc2822_address_header( COMMASPACE.join(email_bcc)) msg['Date'] = formatdate() # Custom headers may override normal headers or provide additional ones for key, value in headers.items(): msg[pycompat.to_text(ustr(key))] = encode_header(value) if subtype == 'html' and not body_alternative: # Always provide alternative text body ourselves if possible. text = html2text.html2text(email_body) alternative_part = MIMEMultipart(_subtype="alternative") alternative_part.attach( MIMEText(text, _charset='utf-8', _subtype='plain')) alternative_part.attach(email_text_part) msg.attach(alternative_part) elif body_alternative: # Include both alternatives, as specified, within a multipart/alternative part alternative_part = MIMEMultipart(_subtype="alternative") body_alternative_ = ustr(body_alternative) alternative_body_part = MIMEText(body_alternative_, _subtype=subtype_alternative, _charset='utf-8') alternative_part.attach(alternative_body_part) alternative_part.attach(email_text_part) msg.attach(alternative_part) else: msg.attach(email_text_part) if attachments: for (fname, fcontent, mime) in attachments: filename_rfc2047 = encode_header_param(fname) if mime and '/' in mime: maintype, subtype = mime.split('/', 1) part = MIMEBase(maintype, subtype) else: part = MIMEBase('application', "octet-stream") # The default RFC2231 encoding of Message.add_header() works in Thunderbird but not GMail # so we fix it by using RFC2047 encoding for the filename instead. part.set_param('name', filename_rfc2047) part.add_header('Content-Disposition', 'attachment', filename=filename_rfc2047) part.set_payload(fcontent) encoders.encode_base64(part) msg.attach(part) return msg
def create(sender, recipients=None, cc=None, bcc=None, subject='', message='', html_message='', context=None, scheduled_time=None, expires_at=None, headers=None, template=None, priority=None, render_on_delivery=False, commit=True, backend=''): """ Creates an email from supplied keyword arguments. If template is specified, email subject and content will be rendered during delivery. """ priority = parse_priority(priority) status = None if priority == PRIORITY.now else STATUS.queued if recipients is None: recipients = [] if cc is None: cc = [] if bcc is None: bcc = [] if context is None: context = '' message_id = make_msgid(domain=get_message_id_fqdn()) if get_message_id_enabled() else None # If email is to be rendered during delivery, save all necessary # information if render_on_delivery: email = Email( from_email=sender, to=recipients, cc=cc, bcc=bcc, scheduled_time=scheduled_time, expires_at=expires_at, message_id=message_id, headers=headers, priority=priority, status=status, context=context, template=template, backend_alias=backend ) else: if template: subject = template.subject message = template.content html_message = template.html_content _context = Context(context or {}) subject = Template(subject).render(_context) message = Template(message).render(_context) html_message = Template(html_message).render(_context) email = Email( from_email=sender, to=recipients, cc=cc, bcc=bcc, subject=subject, message=message, html_message=html_message, scheduled_time=scheduled_time, expires_at=expires_at, message_id=message_id, headers=headers, priority=priority, status=status, backend_alias=backend ) if commit: email.save() return email
def build_email(self, email_from, email_to, subject, body, email_cc=None, email_bcc=None, reply_to=False, attachments=None, message_id=None, references=None, object_id=False, subtype='plain', headers=None, body_alternative=None, subtype_alternative='plain'): """Constructs an RFC2822 email.message.Message object based on the keyword arguments passed, and returns it. :param string email_from: sender email address :param list email_to: list of recipient addresses (to be joined with commas) :param string subject: email subject (no pre-encoding/quoting necessary) :param string body: email body, of the type ``subtype`` (by default, plaintext). If html subtype is used, the message will be automatically converted to plaintext and wrapped in multipart/alternative, unless an explicit ``body_alternative`` version is passed. :param string body_alternative: optional alternative body, of the type specified in ``subtype_alternative`` :param string reply_to: optional value of Reply-To header :param string object_id: optional tracking identifier, to be included in the message-id for recognizing replies. Suggested format for object-id is "res_id-model", e.g. "12345-crm.lead". :param string subtype: optional mime subtype for the text body (usually 'plain' or 'html'), must match the format of the ``body`` parameter. Default is 'plain', making the content part of the mail "text/plain". :param string subtype_alternative: optional mime subtype of ``body_alternative`` (usually 'plain' or 'html'). Default is 'plain'. :param list attachments: list of (filename, filecontents) pairs, where filecontents is a string containing the bytes of the attachment :param list email_cc: optional list of string values for CC header (to be joined with commas) :param list email_bcc: optional list of string values for BCC header (to be joined with commas) :param dict headers: optional map of headers to set on the outgoing mail (may override the other headers, including Subject, Reply-To, Message-Id, etc.) :rtype: email.message.EmailMessage :return: the new RFC2822 email message """ email_from = email_from or self._get_default_from_address() assert email_from, "You must either provide a sender address explicitly or configure "\ "using the combintion of `mail.catchall.domain` and `mail.default.from` "\ "ICPs, in the server configuration file or with the "\ "--email-from startup parameter." headers = headers or {} # need valid dict later email_cc = email_cc or [] email_bcc = email_bcc or [] body = body or u'' msg = EmailMessage(policy=email.policy.SMTP) msg.set_charset('utf-8') if not message_id: if object_id: message_id = tools.generate_tracking_message_id(object_id) else: message_id = make_msgid() msg['Message-Id'] = message_id if references: msg['references'] = references msg['Subject'] = subject msg['From'] = email_from del msg['Reply-To'] msg['Reply-To'] = reply_to or email_from msg['To'] = email_to if email_cc: msg['Cc'] = email_cc if email_bcc: msg['Bcc'] = email_bcc msg['Date'] = datetime.datetime.utcnow() for key, value in headers.items(): msg[pycompat.to_text(ustr(key))] = value email_body = ustr(body) if subtype == 'html' and not body_alternative: msg.add_alternative(html2text.html2text(email_body), subtype='plain', charset='utf-8') msg.add_alternative(email_body, subtype=subtype, charset='utf-8') elif body_alternative: msg.add_alternative(ustr(body_alternative), subtype=subtype_alternative, charset='utf-8') msg.add_alternative(email_body, subtype=subtype, charset='utf-8') else: msg.set_content(email_body, subtype=subtype, charset='utf-8') if attachments: for (fname, fcontent, mime) in attachments: maintype, subtype = mime.split( '/') if mime and '/' in mime else ('application', 'octet-stream') msg.add_attachment(fcontent, maintype, subtype, filename=fname) return msg
def send_email(subject, body, recipients, sender=None, bcc=None, attempts=3): """Send email. subject: email's subject body: email's body recipients: an email address as a string or an iterable of email addresses sender: the email address of the sender. default value taken from config """ if isinstance(subject, str): subject = subject.decode('utf-8', 'ignore') if not sender: sender = config.EMAIL_FROM if isinstance(recipients, basestring): recipients = [recipients] headers = [ "From: %s" % sender, "To: %s" % ", ".join(recipients), "Subject: %s" % subject, "Date: %s" % formatdate(), "Message-ID: %s" % make_msgid() ] if bcc: headers.append("Bcc: %s" % bcc) recipients.append(bcc) if isinstance(body, str): body = body.decode('utf8') message = "%s\r\n\r\n%s" % ("\r\n".join(headers), body) message = message.encode('utf-8', 'ignore') mail_settings = config.MAILER_SETTINGS host = mail_settings.get('mail.host') port = mail_settings.get('mail.port', '5555') username = mail_settings.get('mail.username') password = mail_settings.get('mail.password') tls = mail_settings.get('mail.tls') starttls = mail_settings.get('mail.starttls') # try 3 times to circumvent network issues for attempt in range(attempts): try: if tls and not starttls: server = smtplib.SMTP_SSL(host, port) else: server = smtplib.SMTP(host, port) if tls and starttls: server.starttls() if username: server.login(username, password) ret = server.sendmail(sender, recipients, message) server.quit() return True except smtplib.SMTPException as exc: if attempt == attempts - 1: log.error("Could not send email after %d retries! Error: %r", attempts, exc) return False else: log.warn("Could not send email! Error: %r", exc) log.warn("Retrying in 5 seconds...") sleep(5)
def __init__(self, message): self.message = message self.message_id = message.message_id or make_msgid() self.references = message.references
def message_id_generator(): rstring = ''.join(random.choice(string.ascii_letters) for x in range(13)) return make_msgid(domain='mail.gmail.com', idstring=rstring)
def send_raw_email(self): self.queue[self.current]['starttime'] = datetime.now() self.UIqueue[self.current]['formStarttime'] = self.queue[ self.current]['starttime'] self.queue[self.current]['status'] = STAT_STARTED self.UIqueue[self.current]['status'] = _('Started') obj = self.queue[self.current] # create MIME message msg = MIMEMultipart() msg['Subject'] = self.queue[self.current]['subject'] msg['Message-Id'] = make_msgid('calibre-web') msg['Date'] = formatdate(localtime=True) text = self.queue[self.current]['text'] msg.attach(MIMEText(text.encode('UTF-8'), 'plain', 'UTF-8')) if obj['attachment']: result = get_attachment(obj['filepath'], obj['attachment']) if result: msg.attach(result) else: self._handleError(u"Attachment not found") return msg['From'] = obj['settings']["mail_from"] msg['To'] = obj['recipent'] use_ssl = int(obj['settings'].get('mail_use_ssl', 0)) try: # convert MIME message to string fp = StringIO() gen = Generator(fp, mangle_from_=False) gen.flatten(msg) msg = fp.getvalue() # send email timeout = 600 # set timeout to 5mins org_stderr = sys.stderr sys.stderr = StderrLogger() if use_ssl == 2: self.asyncSMTP = email_SSL(obj['settings']["mail_server"], obj['settings']["mail_port"], timeout) else: self.asyncSMTP = email(obj['settings']["mail_server"], obj['settings']["mail_port"], timeout) # link to logginglevel if web.ub.config.config_log_level != logging.DEBUG: self.asyncSMTP.set_debuglevel(0) else: self.asyncSMTP.set_debuglevel(1) if use_ssl == 1: self.asyncSMTP.starttls() if obj['settings']["mail_password"]: self.asyncSMTP.login(str(obj['settings']["mail_login"]), str(obj['settings']["mail_password"])) self.asyncSMTP.sendmail(obj['settings']["mail_from"], obj['recipent'], msg) self.asyncSMTP.quit() self._handleSuccess() sys.stderr = org_stderr except (MemoryError) as e: self._handleError(u'Error sending email: ' + e.message) return None except (smtplib.SMTPException) as e: self._handleError(u'Error sending email: ' + e.smtp_error.replace("\n", '. ')) return None except (socket.error) as e: self._handleError(u'Error sending email: ' + e.strerror) return None