def send(self, from_addr, recipients, message): # Ensure the message complies with RFC2822: use CRLF line endings message = CRLF.join(self.crlf.split(message)) self.log.info("Sending notification through SMTP at %s:%d to %s" % (self.smtp_server, self.smtp_port, recipients)) server = smtplib.SMTP(self.smtp_server, self.smtp_port) # server.set_debuglevel(True) if self.use_tls: server.ehlo() if not server.esmtp_features.has_key('starttls'): raise TracError(_("TLS enabled but server does not support " \ "TLS")) server.starttls() server.ehlo() if self.smtp_user: server.login(self.smtp_user.encode('utf-8'), self.smtp_password.encode('utf-8')) start = time.time() server.sendmail(from_addr, recipients, message) t = time.time() - start if t > 5: self.log.warning('Slow mail submission (%.2f s), ' 'check your mail setup' % t) if self.use_tls: # avoid false failure detection when the server closes # the SMTP connection with TLS enabled import socket try: server.quit() except socket.sslerror: pass else: server.quit()
def format_props(self): tkt = self.ticket fields = [f for f in tkt.fields if f['name'] not in ('summary', 'cc')] width = [0, 0, 0, 0] i = 0 for f in [f['name'] for f in fields if f['type'] != 'textarea']: if not tkt.values.has_key(f): continue fval = tkt[f] or '' if fval.find('\n') != -1: continue idx = 2 * (i % 2) if len(f) > width[idx]: width[idx] = len(f) if len(fval) > width[idx + 1]: width[idx + 1] = len(fval) i += 1 format = ('%%%is: %%-%is | ' % (width[0], width[1]), ' %%%is: %%-%is%s' % (width[2], width[3], CRLF)) l = (width[0] + width[1] + 5) sep = l * '-' + '+' + (self.COLS - l) * '-' txt = sep + CRLF big = [] i = 0 for f in [f for f in fields if f['name'] != 'description']: fname = f['name'] if not tkt.values.has_key(fname): continue fval = tkt[fname] or '' if fname in ['owner', 'reporter']: fval = obfuscate_email_address(fval) if f['type'] == 'textarea' or '\n' in unicode(fval): big.append((fname.capitalize(), CRLF.join(fval.splitlines()))) else: txt += format[i % 2] % (fname.capitalize(), fval) i += 1 if i % 2: txt += CRLF if big: txt += sep for name, value in big: txt += CRLF.join(['', name + ':', value, '', '']) txt += sep return txt
def format_props(self): tkt = self.ticket fields = [f for f in tkt.fields if f['name'] not in ('summary', 'cc')] width = [0, 0, 0, 0] i = 0 for f in [f['name'] for f in fields if f['type'] != 'textarea']: if not tkt.values.has_key(f): continue fval = tkt[f] if fval.find('\n') != -1: continue idx = 2 * (i % 2) if len(f) > width[idx]: width[idx] = len(f) if len(fval) > width[idx + 1]: width[idx + 1] = len(fval) i += 1 format = ('%%%is: %%-%is | ' % (width[0], width[1]), ' %%%is: %%-%is%s' % (width[2], width[3], CRLF)) l = (width[0] + width[1] + 5) sep = l * '-' + '+' + (self.COLS - l) * '-' txt = sep + CRLF big = [] i = 0 for f in [f for f in fields if f['name'] != 'description']: fname = f['name'] if not tkt.values.has_key(fname): continue fval = tkt[fname] if f['type'] == 'textarea' or '\n' in unicode(fval): big.append((fname.capitalize(), CRLF.join(fval.splitlines()))) else: txt += format[i % 2] % (fname.capitalize(), fval) i += 1 if i % 2: txt += CRLF if big: txt += sep for name, value in big: txt += CRLF.join(['', name + ':', value, '', '']) txt += sep return txt
def format_props(self): tkt = self.ticket fields = [f for f in tkt.fields if f["name"] not in ("summary", "cc", "time", "changetime")] width = [0, 0, 0, 0] i = 0 for f in fields: if f["type"] == "textarea": continue fname = f["name"] if not fname in tkt.values: continue fval = tkt[fname] or "" if fval.find("\n") != -1: continue if fname in ["owner", "reporter"]: fval = obfuscate_email_address(fval) idx = 2 * (i % 2) width[idx] = max(self.get_text_width(f["label"]), width[idx]) width[idx + 1] = max(self.get_text_width(fval), width[idx + 1]) i += 1 width_l = width[0] + width[1] + 5 width_r = width[2] + width[3] + 5 half_cols = (self.COLS - 1) / 2 if width_l + width_r + 1 > self.COLS: if (width_l > half_cols and width_r > half_cols) or (width[0] > half_cols / 2 or width[2] > half_cols / 2): width_l = half_cols width_r = half_cols elif width_l > width_r: width_l = min((self.COLS - 1) * 2 / 3, width_l) width_r = self.COLS - width_l - 1 else: width_r = min((self.COLS - 1) * 2 / 3, width_r) width_l = self.COLS - width_r - 1 sep = width_l * "-" + "+" + width_r * "-" txt = sep + CRLF cell_tmp = [u"", u""] big = [] i = 0 width_lr = [width_l, width_r] for f in [f for f in fields if f["name"] != "description"]: fname = f["name"] if not tkt.values.has_key(fname): continue fval = tkt[fname] or "" if fname in ["owner", "reporter"]: fval = obfuscate_email_address(fval) if f["type"] == "textarea" or "\n" in unicode(fval): big.append((f["label"], CRLF.join(fval.splitlines()))) else: # Note: f['label'] is a Babel's LazyObject, make sure its # __str__ method won't be called. str_tmp = u"%s: %s" % (f["label"], unicode(fval)) idx = i % 2 cell_tmp[idx] += wrap( str_tmp, width_lr[idx] - 2 + 2 * idx, (width[2 * idx] - self.get_text_width(f["label"]) + 2 * idx) * " ", 2 * " ", CRLF, ) cell_tmp[idx] += CRLF i += 1 cell_l = cell_tmp[0].splitlines() cell_r = cell_tmp[1].splitlines() for i in range(max(len(cell_l), len(cell_r))): if i >= len(cell_l): cell_l.append(width_l * " ") elif i >= len(cell_r): cell_r.append("") fmt_width = width_l - self.get_text_width(cell_l[i]) + len(cell_l[i]) txt += u"%-*s|%s%s" % (fmt_width, cell_l[i], cell_r[i], CRLF) if big: txt += sep for name, value in big: txt += CRLF.join(["", name + ":", value, "", ""]) txt += sep return txt
def send(self, torcpts, ccrcpts, mime_headers={}): from email.MIMEText import MIMEText from email.Utils import formatdate stream = self.template.generate(**self.data) body = stream.render('text') projname = self.config.get('project', 'name') public_cc = self.config.getbool('notification', 'use_public_cc') headers = {} headers['X-Mailer'] = 'Trac %s, by Edgewall Software' % __version__ headers['X-Trac-Version'] = __version__ headers['X-Trac-Project'] = projname headers['X-URL'] = self.config.get('project', 'url') headers['Precedence'] = 'bulk' headers['Auto-Submitted'] = 'auto-generated' headers['Subject'] = self.subject headers['From'] = (self.from_name or projname, self.from_email) headers['Reply-To'] = self.replyto_email def build_addresses(rcpts): """Format and remove invalid addresses""" return filter(lambda x: x, \ [self.get_smtp_address(addr) for addr in rcpts]) def remove_dup(rcpts, all): """Remove duplicates""" tmp = [] for rcpt in rcpts: if not rcpt in all: tmp.append(rcpt) all.append(rcpt) return (tmp, all) toaddrs = build_addresses(torcpts) ccaddrs = build_addresses(ccrcpts) recipients = [] (toaddrs, recipients) = remove_dup(toaddrs, recipients) (ccaddrs, recipients) = remove_dup(ccaddrs, recipients) # if there is not valid recipient, leave immediately if len(recipients) < 1: self.env.log.info('no recipient for account change notification') return pcc = [] if public_cc: pcc += ccaddrs if toaddrs: headers['To'] = ', '.join(toaddrs) if pcc: headers['Cc'] = ', '.join(pcc) headers['Date'] = formatdate() # sanity check if not self._charset.body_encoding: try: dummy = body.encode('ascii') except UnicodeDecodeError: raise TracError(_("Ticket contains non-ASCII chars. " \ "Please change encoding setting")) msg = MIMEText(body, 'plain') # Message class computes the wrong type from MIMEText constructor, # which does not take a Charset object as initializer. Reset the # encoding type to force a new, valid evaluation del msg['Content-Transfer-Encoding'] msg.set_charset(self._charset) self.add_headers(msg, headers); self.add_headers(msg, mime_headers); self.env.log.info("Sending SMTP notification to %s"%recipients) msgtext = msg.as_string() # Ensure the message complies with RFC2822: use CRLF line endings recrlf = re.compile("\r?\n") msgtext = CRLF.join(recrlf.split(msgtext)) NotificationSystem(self.env).send_email(msg['From'], recipients, msgtext)
def send(self, torcpts, ccrcpts, mime_headers={}): """ this method is based NotifyEmail in trac/notification.py As the default trac NotifyEmail class assumes alot, and will overwrite headers we do not call our ancestor class method here, but send the mail direct """ from email.MIMEText import MIMEText from email.Utils import formatdate stream = self.template.generate(**self.data) body = stream.render('text') projname = self.config.get('project', 'name') headers = {} headers['X-Mailer'] = 'Trac %s, by Edgewall Software' % __version__ headers['X-Trac-Version'] = __version__ headers['X-Trac-Project'] = projname headers['X-URL'] = self.env.project_url headers['Precedence'] = 'bulk' headers['Auto-Submitted'] = 'auto-generated' headers['Subject'] = self.subject headers['From'] = (self.from_name or projname, self.from_email) headers['Reply-To'] = self.reply_to_email # add Message-ID and In-Reply-To for threaded mail clients if self.action == 'post_created': headers['Message-ID'] = self.get_message_id(projname, self.blog.name) else: headers['Message-ID'] = self.get_message_id(projname, self.blog.name, self.time) headers['In-Reply-To'] = headers['References'] = self.get_message_id(projname, self.blog.name) def build_addresses(rcpts): """Format and remove invalid addresses""" return filter(lambda x: x, [self.get_smtp_address(addr) for addr in rcpts]) def remove_dup(rcpts, all): """Remove duplicates""" tmp = [] for rcpt in rcpts: if not rcpt in all: tmp.append(rcpt) all.append(rcpt) return (tmp, all) toaddrs = build_addresses(torcpts) ccaddrs = build_addresses(ccrcpts) accparam = self.config.getlist('fullblog-notification', 'smtp_always_cc') accaddrs = accparam and build_addresses(accparam) or [] recipients = [] (toaddrs, recipients) = remove_dup(toaddrs, recipients) (ccaddrs, recipients) = remove_dup(ccaddrs, recipients) (accaddrs, recipients) = remove_dup(accaddrs, recipients) # if there is not valid recipient, leave immediately if len(recipients) < 1: self.env.log.info('no recipient for a fullblog notification') return cc = accaddrs + ccaddrs if cc: headers['Cc'] = ', '.join(cc) if toaddrs: headers['To'] = ', '.join(toaddrs) headers['Date'] = formatdate() # sanity check if not self._charset.body_encoding: try: dummy = body.encode('ascii') except UnicodeDecodeError: raise TracError(_("Blog post contains non-Ascii chars. " \ "Please change encoding setting")) msg = MIMEText(body, 'plain') # Message class computes the wrong type from MIMEText constructor, # which does not take a Charset object as initializer. Reset the # encoding type to force a new, valid evaluation del msg['Content-Transfer-Encoding'] msg.set_charset(self._charset) self.add_headers(msg, headers); self.add_headers(msg, mime_headers); self.env.log.info("Sending SMTP notification to %s:%d to %s" % (self.smtp_server, self.smtp_port, recipients)) msgtext = msg.as_string() # Ensure the message complies with RFC2822: use CRLF line endings recrlf = re.compile("\r?\n") msgtext = CRLF.join(recrlf.split(msgtext)) try: self.server.sendmail(msg['From'], recipients, msgtext) except Exception, err: self.env.log.debug('Notification could not be sent: %r', err)
def format_props(self): tkt = self.ticket fields = [f for f in tkt.fields if f['name'] not in ('summary', 'cc', 'time', 'changetime')] width = [0, 0, 0, 0] i = 0 for f in fields: if f['type'] == 'textarea': continue fname = f['name'] if not fname in tkt.values: continue fval = tkt[fname] or '' if fval.find('\n') != -1: continue if fname in ['owner', 'reporter']: fval = obfuscate_email_address(fval) idx = 2 * (i % 2) width[idx] = max(self.get_text_width(f['label']), width[idx]) width[idx + 1] = max(self.get_text_width(fval), width[idx + 1]) i += 1 width_l = width[0] + width[1] + 5 width_r = width[2] + width[3] + 5 half_cols = (self.COLS - 1) / 2 if width_l + width_r + 1 > self.COLS: if ((width_l > half_cols and width_r > half_cols) or (width[0] > half_cols / 2 or width[2] > half_cols / 2)): width_l = half_cols width_r = half_cols elif width_l > width_r: width_l = min((self.COLS - 1) * 2 / 3, width_l) width_r = self.COLS - width_l - 1 else: width_r = min((self.COLS - 1) * 2 / 3, width_r) width_l = self.COLS - width_r - 1 sep = width_l * '-' + '+' + width_r * '-' txt = sep + CRLF cell_tmp = [u'', u''] big = [] i = 0 width_lr = [width_l, width_r] for f in [f for f in fields if f['name'] != 'description']: fname = f['name'] if not tkt.values.has_key(fname): continue fval = tkt[fname] or '' if fname in ['owner', 'reporter']: fval = obfuscate_email_address(fval) if f['type'] == 'textarea' or '\n' in unicode(fval): big.append((f['label'], CRLF.join(fval.splitlines()))) else: # Note: f['label'] is a Babel's LazyObject, make sure its # __str__ method won't be called. str_tmp = u'%s: %s' % (f['label'], unicode(fval)) idx = i % 2 cell_tmp[idx] += wrap(str_tmp, width_lr[idx] - 2 + 2 * idx, (width[2 * idx] - self.get_text_width(f['label']) + 2 * idx) * ' ', 2 * ' ', CRLF) cell_tmp[idx] += CRLF i += 1 cell_l = cell_tmp[0].splitlines() cell_r = cell_tmp[1].splitlines() for i in range(max(len(cell_l), len(cell_r))): if i >= len(cell_l): cell_l.append(width_l * ' ') elif i >= len(cell_r): cell_r.append('') fmt_width = width_l - self.get_text_width(cell_l[i]) \ + len(cell_l[i]) txt += u'%-*s|%s%s' % (fmt_width, cell_l[i], cell_r[i], CRLF) if big: txt += sep for name, value in big: txt += CRLF.join(['', name + ':', value, '', '']) txt += sep return txt
def send(self, from_addr, recipients, message): """Send message to recipients via e-mail.""" # Ensure the message complies with RFC2822: use CRLF line endings message = CRLF.join(re.split("\r?\n", message)) self.email_sender.send(from_addr, recipients, message)
def send(self, from_addr, recipients, message): """Send message to recipients via e-mail.""" # Ensure the message complies with RFC2822: use CRLF line endings message = CRLF.join(re.split('\r?\n', message)) self.email_sender.send(from_addr, recipients, message)
def send(self, torcpts, ccrcpts, mime_headers={}): from email.MIMEText import MIMEText from email.Utils import formatdate stream = self.template.generate(**self.data) body = stream.render('text') projname = self.config.get('project', 'name') public_cc = self.config.getbool('notification', 'use_public_cc') headers = {} headers['X-Mailer'] = 'Trac %s, by Edgewall Software' % __version__ headers['X-Trac-Version'] = __version__ headers['X-Trac-Project'] = projname headers['X-URL'] = self.config.get('project', 'url') headers['Precedence'] = 'bulk' headers['Auto-Submitted'] = 'auto-generated' headers['Subject'] = self.subject headers['From'] = (self.from_name or projname, self.from_email) headers['Reply-To'] = self.replyto_email def build_addresses(rcpts): """Format and remove invalid addresses""" return filter(lambda x: x, \ [self.get_smtp_address(addr) for addr in rcpts]) def remove_dup(rcpts, all): """Remove duplicates""" tmp = [] for rcpt in rcpts: if not rcpt in all: tmp.append(rcpt) all.append(rcpt) return (tmp, all) toaddrs = build_addresses(torcpts) ccaddrs = build_addresses(ccrcpts) accparam = self.config.get('notification', 'smtp_always_cc') accaddrs = accparam and \ build_addresses(accparam.replace(',', ' ').split()) or [] bccparam = self.config.get('notification', 'smtp_always_bcc') bccaddrs = bccparam and \ build_addresses(bccparam.replace(',', ' ').split()) or [] recipients = [] (toaddrs, recipients) = remove_dup(toaddrs, recipients) (ccaddrs, recipients) = remove_dup(ccaddrs, recipients) (accaddrs, recipients) = remove_dup(accaddrs, recipients) (bccaddrs, recipients) = remove_dup(bccaddrs, recipients) # if there is not valid recipient, leave immediately if len(recipients) < 1: self.env.log.info('no recipient for a ticket notification') return pcc = accaddrs if public_cc: pcc += ccaddrs if toaddrs: headers['To'] = ', '.join(toaddrs) if pcc: headers['Cc'] = ', '.join(pcc) headers['Date'] = formatdate() msg = MIMEText(body, 'plain') # Message class computes the wrong type from MIMEText constructor, # which does not take a Charset object as initializer. Reset the # encoding type to force a new, valid evaluation del msg['Content-Transfer-Encoding'] msg.set_charset(self._charset) self.add_headers(msg, headers); self.add_headers(msg, mime_headers); self.env.log.info("Sending SMTP notification to %s:%d to %s" % (self.smtp_server, self.smtp_port, recipients)) msgtext = msg.as_string() # Ensure the message complies with RFC2822: use CRLF line endings recrlf = re.compile("\r?\n") msgtext = CRLF.join(recrlf.split(msgtext)) start = time.time() self.server.sendmail(msg['From'], recipients, msgtext) t = time.time() - start if t > 5: self.env.log.warning('Slow mail submission (%.2f s), ' 'check your mail setup' % t)