def cleanup_message(message, addr_headers=ADDR_HEADERS, param_headers=PARAM_HEADERS): """ Cleanup a `Message` handling header and payload charsets. Headers are handled in the most sane way possible. Address names are left in `ascii` if possible or encoded to `iso-8859-1` or `utf-8` and finally encoded according to RFC 2047 without encoding the address, something the `email` stdlib package doesn't do. Parameterized headers such as `filename` in the `Content-Disposition` header, have their values encoded properly while leaving the rest of the header to be handled without encoding. Finally, all other header are left in `ascii` if possible or encoded to `iso-8859-1` or `utf-8` as a whole. The message is modified in place and is also returned in such a state that it can be safely encoded to ascii. """ for key, value in message.items(): if key.lower() in addr_headers: addrs = [] for name, addr in utils.getaddresses([value]): best, encoded = best_charset(name) if PY_2: name = encoded name = charset.Charset(best).header_encode(name) addrs.append(utils.formataddr((name, addr))) value = ', '.join(addrs) message.replace_header(key, value) if key.lower() in param_headers: for param_key, param_value in message.get_params(header=key): if param_value: best, encoded = best_charset(param_value) if PY_2: param_value = encoded if best == 'ascii': best = None message.set_param(param_key, param_value, header=key, charset=best) else: best, encoded = best_charset(value) if PY_2: value = encoded value = charset.Charset(best).header_encode(value) message.replace_header(key, value) payload = message.get_payload() if payload and isinstance(payload, text_type): best, encoded = best_charset(payload) if PY_2: payload = encoded message.set_payload(payload, charset=best) elif isinstance(payload, list): for part in payload: cleanup_message(part) return message
def formatMail(mailText): """returns a mail with headers and content properly formatted as a bytestring and MIME. mailText must be a unicode instance or pure ASCII """ rawHeaders, rawBody = mailText.split("\n\n", 1) cs = charset.Charset("utf-8") cs.body_encoding = charset.QP cs.header_encoding = charset.QP # they've botched MIMEText so bad it can't really generate # quoted-printable UTF-8 any more. So, let's forget MIMEText: msg = MIMENonMultipart("text", "plain", charset="utf-8") msg.set_payload(rawBody, charset=cs) for key, value in Parser().parsestr(rawHeaders.encode("utf-8")).items(): if re.match("[ -~]*$", value): # it's plain ASCII, don't needlessly uglify output msg[key] = value else: msg[key] = Header(value, cs) msg["Date"] = emailutils.formatdate(time.time(), localtime=False, usegmt=True) msg["X-Mailer"] = "DaCHS VO Server" return msg.as_string()
def sendReport(file_new): print('1') #计算case通过率 with open(file_new, 'rb') as f: chst = charset.Charset(input_charset='utf-8') htmlf = open(file_new, 'r', encoding="utf-8") mail_body = htmlf.read() msg = MIMEText( '<html><body><h1>hi,all</h1>' + '<h2>测试内容:登录,借款等</h2>' + '<h3>如下报告不可点击,要查看详细:<a href= "file:///G:/liuyinchun/tianbaodai/tianbaodai_report/report' + now + '.html"' + '>click here</a>...</h3>' + '</body></html>' + mail_body, 'html', 'utf-8') msg['Subject'] = Header(u'天宝贷ui自动化测试报告') msg['From'] = "*****@*****.**" msg['To'] = "*****@*****.**" msg['Cc'] = "*****@*****.**" smtp = smtplib.SMTP_SSL('smtp.exmail.qq.com', port=465) #端口smtp smtp.login('*****@*****.**', 'Liuyc2017') smtp.sendmail(msg['From'], msg['To'].split(';') + msg['Cc'].split(';'), msg.as_string().encode('utf-8')) smtp.quit() print('test report has send out!')
def hack_to_use_quopri(message): """ force message payload to be encoded using quoted-printable http://mail.python.org/pipermail/baypiggies/2008-September/003984.html """ charset = email_charset.Charset('utf-8') charset.header_encoding = email_charset.QP charset.body_encoding = email_charset.QP del message['Content-Transfer-Encoding'] message.set_charset(charset)
def test_createEmail_message_content_transfer_encoding_8bit(self): # buildbot.reporters.mail.ENCODING is 'utf8' # On Python 3, the body_encoding for 'utf8' is base64. # On Python 2, the body_encoding for 'utf8' is None. # If the body_encoding is None, the email package # will try to deduce the 'Content-Transfer-Encoding' # by calling email.encoders.encode_7or8bit(). # If the foo.encode('ascii') works on the body, it input_charset = charset.Charset(mail.ENCODING) if input_charset.body_encoding == charset.BASE64: expEncoding = 'base64' elif input_charset.body_encoding is None: expEncoding = '8bit' return self.do_test_createEmail_cte(u"\U0001F4A7", expEncoding)
def _send(self, email_message): """A helper method that does the actual sending.""" if not email_message.recipients(): return False encoding = email_message.encoding or charset.Charset('utf-8') from_email = email_message.from_email recipients = email_message.recipients() message = email_message.message() try: self.connection.sendmail(from_email, recipients, as_bytes(message, linesep='\r\n')) except smtplib.SMTPException: if not self.fail_silently: raise return False return True
def start_mail_thread(subject, message, receivers): c = charset.Charset() c.header_encoding = charset.BASE64 c.body_encoding = charset.BASE64 # c.input_charset = 'utf-8' msg = MIMEText(message, 'html', 'utf-8') h = Header(subject, c) sender = settings.DEFAULT_FROM_EMAIL msg['Subject'] = h msg['From'] = "%s <%s>" % (Header("QJob社交招聘", c).encode("utf-8"), sender) msg['To'] = ','.join(receivers) smtp = SMTP(settings.EMAIL_HOST, settings.EMAIL_PORT) # smtp.login(settings.EMAIL_HOST_USER, settings.EMAIL_HOST_PASSWORD) new_thread = Thread(target=smtp.sendmail, args=[sender, receivers, msg.as_string()], daemon=True) new_thread.start()
def send_smtp(to="", subject="", plaintext="", html=""): """ Send an email. """ # Create message container msg = MIMENonMultipart("text", "plain", charset="utf-8") # Construct a new charset which uses Quoted Printables (base64 is default) cs = charset.Charset("utf-8") cs.body_encoding = charset.QP msg["Subject"] = subject msg["From"] = application.config["MAIL_DEFAULT_SENDER"] msg["To"] = to msg.set_payload(plaintext, charset=cs) try: s = smtplib.SMTP(application.config["MAIL_SERVER"]) if application.config["MAIL_USERNAME"] is not None: s.login( application.config["MAIL_USERNAME"], application.config["MAIL_PASSWORD"], ) except ConnectionRefusedError: print("Problem when sending email.") except Exception: logger.exception("send_smtp raised:") else: try: s.sendmail( application.config["MAIL_DEFAULT_SENDER"], msg["To"], msg.as_bytes().decode(encoding="UTF-8"), ) s.quit() except Exception: pass
def force_text(val): if is_lazy_string(val): val = val.value return str(val) def to_unicode(text): return text.encode('UTF-8') # Don't BASE64-encode UTF-8 messages so that we avoid unwanted attention from # some spam filters. utf8_charset = Charset.Charset('UTF-8') utf8_charset.body_encoding = None # Python defaults to BASE64 utf8_charset_qp = Charset.Charset('UTF-8') utf8_charset_qp.body_encoding = Charset.QP # Default MIME type to use on attachments (if it is not explicitly given # and cannot be guessed). DEFAULT_ATTACHMENT_MIME_TYPE = 'application/octet-stream' RFC5322_EMAIL_LINE_LENGTH_LIMIT = 998 class BadHeaderError(ValueError): pass
from email.message import Message from email.mime.base import MIMEBase from email.mime.message import MIMEMessage from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.utils import formatdate, getaddresses, make_msgid, parseaddr from io import BytesIO, StringIO from pathlib import Path from django.conf import settings from django.core.mail.utils import DNS_NAME from django.utils.encoding import force_text # Don't BASE64-encode UTF-8 messages so that we avoid unwanted attention from # some spam filters. utf8_charset = Charset.Charset("utf-8") utf8_charset.body_encoding = None # Python defaults to BASE64 utf8_charset_qp = Charset.Charset("utf-8") utf8_charset_qp.body_encoding = Charset.QP # Default MIME type to use on attachments (if it is not explicitly given # and cannot be guessed). DEFAULT_ATTACHMENT_MIME_TYPE = "application/octet-stream" RFC5322_EMAIL_LINE_LENGTH_LIMIT = 998 class BadHeaderError(ValueError): pass
def send_via_smtp(self, email_from_smtp, key, email_from, email_to, subject, html_text, plain_text, cid_images, attachments): """ Отправить сообщение через SMTP :param email_from_smtp: имя smtp сервера :param key: пароль :param email_from: от кого отправляется сообщение :param password: пароль почтового ящика :param email_to: кому отправляется сообщение :param subject: тема сообщения :param html_text: текст в формате HTML :param plain_text: текст в формате plain :param cid_images: пары текста <content-id>, имя-файла :param attachments: вложения документа """ # Создать корень сообщения и заполнить его заголовки from, to, и subject msgRoot = MIMEMultipart('related') msgRoot['Reply-To'] = email_from msgRoot['From'] = formataddr((str(Header('FooBar', 'utf-8')), email_from)) msgRoot['To'] = email_to msgRoot['Date'] = formatdate(localtime=True) msgRoot['Subject'] = Header(subject, 'utf-8') msgRoot['Organization'] = Header('ООО "FooBar"', 'utf-8') # msgRoot['User-Agent'] = "Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101\n Thunderbird/52.5.2" msgRoot['Content-Language'] = 'ru' # Инкапсулировать plain и HTML версии тела сообщения в части 'alternative', # чтобы mail-агенты могли решить, что они хотят отображать msgAlternative = MIMEMultipart('alternative') # msgAlternative = MIMEMultipart('mixed') msgRoot.attach(msgAlternative) ch = charset.Charset('utf-8') ch.body_encoding = '8bit' msgHtml = MIMEText(plain_text, 'plain', 'utf-8') msgAlternative.attach(msgHtml) msgHtml = MIMEText(html_text, 'html', 'utf-8') msgAlternative.attach(msgHtml) for cid, filename in cid_images: with open(filename, "rb") as f: msgImage = MIMEImage(f.read()) msgImage.add_header('Content-ID', '<' + cid + '>') msgImage.add_header('Content-Disposition', 'inline; filename="' + cid + '"') msgRoot.attach(msgImage) for base, fname in attachments or []: filename = os.path.join(base, fname) with open(filename, "rb") as f: part = MIMEApplication(f.read(), _subtype="pdf", name=Header(fname, maxlinelen=68).encode()) name = "utf-8''" + urllib.parse.quote(fname.encode('utf-8')) # После закрытия файла part[ 'Content-Disposition'] = 'attachment;\n' + self.encode_filename( name) msgRoot.attach(part) s = msgRoot.as_string() if 1: with open("eml.eml", "w") as f: f.write(s) socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS4, pdata.proxy_ip, pdata.proxy_port) socks.wrapmodule(smtplib) server = smtplib.SMTP_SSL(email_from_smtp, 465) # server.ehlo(email_from) server.login(email_from, key) server.sendmail(email_from, email_to, s) # server.sendmail(email_from, email_from, s) server.quit()
def alert_smtp(alert, metric, context): """ Called by :func:`~trigger_alert` and sends an alert via smtp to the recipients that are configured for the metric. """ LOCAL_DEBUG = False logger = logging.getLogger(skyline_app_logger) if settings.ENABLE_DEBUG or LOCAL_DEBUG: logger.info('debug :: alert_smtp - sending smtp alert') logger.info('debug :: alert_smtp - Memory usage at start: %s (kb)' % resource.getrusage(resource.RUSAGE_SELF).ru_maxrss) # FULL_DURATION to hours so that analyzer surfaces the relevant timeseries data # in the graph full_duration_in_hours = int(settings.FULL_DURATION) / 3600 # @added 20161229 - Feature #1830: Ionosphere alerts # Added Ionosphere variables base_name = str(metric[1]).replace(settings.FULL_NAMESPACE, '', 1) if settings.IONOSPHERE_ENABLED: timeseries_dir = base_name.replace('.', '/') training_data_dir = '%s/%s/%s' % (settings.IONOSPHERE_DATA_FOLDER, str(int(metric[2])), timeseries_dir) graphite_image_file = '%s/%s.%s.graphite.%sh.png' % ( training_data_dir, base_name, skyline_app, str(int(full_duration_in_hours))) json_file = '%s/%s.%s.redis.%sh.json' % ( training_data_dir, base_name, skyline_app, str(int(full_duration_in_hours))) training_data_redis_image = '%s/%s.%s.redis.plot.%sh.png' % ( training_data_dir, base_name, skyline_app, str(int(full_duration_in_hours))) # For backwards compatibility if '@' in alert[1]: sender = settings.ALERT_SENDER recipient = alert[1] else: sender = settings.SMTP_OPTS['sender'] # @modified 20160806 - Added default_recipient try: recipients = settings.SMTP_OPTS['recipients'][alert[0]] use_default_recipient = False except: use_default_recipient = True if use_default_recipient: try: recipients = settings.SMTP_OPTS['default_recipient'] logger.info( 'alert_smtp - using default_recipient as no recipients are configured for %s' % str(alert[0])) except: logger.error( 'error :: alert_smtp - no known recipient for %s' % str(alert[0])) return False # Backwards compatibility if type(recipients) is str: recipients = [recipients] # @added 20180524 - Task #2384: Change alerters to cc other recipients # The alerters did send an individual email to each recipient. This would be # more useful if one email was sent with the first smtp recipient being the # to recipient and the subsequent recipients were add in cc. if recipients: primary_recipient = False cc_recipients = False for i_recipient in recipients: if not primary_recipient: primary_recipient = str(i_recipient) if primary_recipient != i_recipient: if not cc_recipients: cc_recipients = str(i_recipient) else: new_cc_recipients = '%s,%s' % (str(cc_recipients), str(i_recipient)) cc_recipients = str(new_cc_recipients) logger.info( 'alert_smtp - will send to primary_recipient :: %s, cc_recipients :: %s' % (str(primary_recipient), str(cc_recipients))) # @modified 20161229 - Feature #1830: Ionosphere alerts # Ionosphere alerts unencoded_graph_title = 'Skyline %s - ALERT at %s hours - %s' % ( context, str(int(full_duration_in_hours)), str(metric[0])) # @modified 20170603 - Feature #2034: analyse_derivatives # Added deriative functions to convert the values of metrics strictly # increasing monotonically to their deriative products in alert graphs and # specify it in the graph_title known_derivative_metric = False try: # @modified 20180519 - Feature #2378: Add redis auth to Skyline and rebrow if settings.REDIS_PASSWORD: REDIS_ALERTER_CONN = redis.StrictRedis( password=settings.REDIS_PASSWORD, unix_socket_path=settings.REDIS_SOCKET_PATH) else: REDIS_ALERTER_CONN = redis.StrictRedis( unix_socket_path=settings.REDIS_SOCKET_PATH) except: logger.error(traceback.format_exc()) logger.error('error :: alert_smtp - redis connection failed') try: derivative_metrics = list( REDIS_ALERTER_CONN.smembers('derivative_metrics')) except: derivative_metrics = [] redis_metric_name = '%s%s' % (settings.FULL_NAMESPACE, str(base_name)) if redis_metric_name in derivative_metrics: known_derivative_metric = True if known_derivative_metric: try: non_derivative_monotonic_metrics = settings.NON_DERIVATIVE_MONOTONIC_METRICS except: non_derivative_monotonic_metrics = [] skip_derivative = in_list(redis_metric_name, non_derivative_monotonic_metrics) if skip_derivative: known_derivative_metric = False if known_derivative_metric: unencoded_graph_title = 'Skyline %s - ALERT at %s hours - derivative graph - %s' % ( context, str(int(full_duration_in_hours)), str(metric[0])) if settings.ENABLE_DEBUG or LOCAL_DEBUG: logger.info('debug :: alert_smtp - unencoded_graph_title: %s' % unencoded_graph_title) graph_title_string = quote(unencoded_graph_title, safe='') graph_title = '&title=%s' % graph_title_string graphite_port = '80' if settings.GRAPHITE_PORT != '': graphite_port = str(settings.GRAPHITE_PORT) link = '%s://%s:%s/render/?from=-%shours&target=cactiStyle(%s)%s%s&colorList=orange' % ( settings.GRAPHITE_PROTOCOL, settings.GRAPHITE_HOST, graphite_port, str(int(full_duration_in_hours)), metric[1], settings.GRAPHITE_GRAPH_SETTINGS, graph_title) # @added 20170603 - Feature #2034: analyse_derivatives if known_derivative_metric: link = '%s://%s:%s/render/?from=-%shours&target=cactiStyle(nonNegativeDerivative(%s))%s%s&colorList=orange' % ( settings.GRAPHITE_PROTOCOL, settings.GRAPHITE_HOST, graphite_port, str(int(full_duration_in_hours)), metric[1], settings.GRAPHITE_GRAPH_SETTINGS, graph_title) content_id = metric[1] image_data = None if settings.SMTP_OPTS.get('embed-images'): # @added 20161229 - Feature #1830: Ionosphere alerts # Use existing data if files exist if os.path.isfile(graphite_image_file): try: with open(graphite_image_file, 'r') as f: image_data = f.read() logger.info('alert_smtp - using existing png - %s' % graphite_image_file) except: logger.error(traceback.format_exc()) logger.error( 'error :: alert_smtp - failed to read image data from existing png - %s' % graphite_image_file) logger.error('error :: alert_smtp - %s' % str(link)) image_data = None if image_data is None: try: # @modified 20170913 - Task #2160: Test skyline with bandit # Added nosec to exclude from bandit tests image_data = urllib2.urlopen(link).read() # nosec if settings.ENABLE_DEBUG or LOCAL_DEBUG: logger.info('debug :: alert_smtp - image data OK') except urllib2.URLError: logger.error(traceback.format_exc()) logger.error('error :: alert_smtp - failed to get image graph') logger.error('error :: alert_smtp - %s' % str(link)) image_data = None if settings.ENABLE_DEBUG or LOCAL_DEBUG: logger.info('debug :: alert_smtp - image data None') if LOCAL_DEBUG: logger.info( 'debug :: alert_smtp - Memory usage after image_data: %s (kb)' % resource.getrusage(resource.RUSAGE_SELF).ru_maxrss) # If we failed to get the image or if it was explicitly disabled, # use the image URL instead of the content. if image_data is None: img_tag = '<img src="%s"/>' % link else: img_tag = '<img src="cid:%s"/>' % content_id if settings.ENABLE_DEBUG or LOCAL_DEBUG: logger.info('debug :: alert_smtp - img_tag: %s' % img_tag) if settings.IONOSPHERE_ENABLED: # Create Ionosphere Graphite image # @modified 20161229 - Feature #1830: Ionosphere alerts # Only write the data to the file if it does not exist if not os.path.isfile(graphite_image_file): try: write_data_to_file(skyline_app, graphite_image_file, 'w', image_data) logger.info('added %s Ionosphere Graphite image :: %s' % (skyline_app, graphite_image_file)) except: logger.info(traceback.format_exc()) logger.error( 'error :: failed to add %s Ionosphere Graphite image' % (skyline_app, graphite_image_file)) else: logger.info( '%s Ionosphere Graphite image already exists :: %s' % (skyline_app, graphite_image_file)) redis_image_data = None try: plot_redis_data = settings.PLOT_REDIS_DATA except: plot_redis_data = False if settings.SMTP_OPTS.get('embed-images') and plot_redis_data: # Create graph from Redis data redis_metric_key = '%s%s' % (settings.FULL_NAMESPACE, metric[1]) try: raw_series = REDIS_ALERTER_CONN.get(redis_metric_key) if settings.ENABLE_DEBUG or LOCAL_DEBUG: logger.info('debug :: alert_smtp - raw_series: %s' % 'OK') except: if settings.ENABLE_DEBUG or LOCAL_DEBUG: logger.info('debug :: alert_smtp - raw_series: %s' % 'FAIL') try: if LOCAL_DEBUG: logger.info( 'debug :: alert_smtp - Memory usage before get Redis timeseries data: %s (kb)' % resource.getrusage(resource.RUSAGE_SELF).ru_maxrss) unpacker = Unpacker(use_list=True) unpacker.feed(raw_series) timeseries_x = [float(item[0]) for item in unpacker] unpacker = Unpacker(use_list=True) unpacker.feed(raw_series) timeseries_y = [item[1] for item in unpacker] unpacker = Unpacker(use_list=False) unpacker.feed(raw_series) timeseries = list(unpacker) if LOCAL_DEBUG: logger.info( 'debug :: alert_smtp - Memory usage after get Redis timeseries data: %s (kb)' % resource.getrusage(resource.RUSAGE_SELF).ru_maxrss) except: logger.error('error :: alert_smtp - unpack timeseries failed') timeseries = None if settings.IONOSPHERE_ENABLED and timeseries: ''' .. todo: this is possibly to be used to allow the user to submit the FULL_DURATION duration data set for the features profile to be created against IF it is a Mirage metric. This would allow for additional granularity in Mirage metrics, thereby maintaining their seasonality, but allow user and Skyline to analyze the anomaly at a FULL_DURATION resolution as well. Not sure how to code that in Ionosphere context yet but could just be additonal flag in the Ionosphere record. In the Ionosphere frontend, the user would be given an option to either create the features profile on the Mirage timeseries or the redis FULL_DURATION timeseries. It is a little complicated, but doable. # @modified 20161229 - Feature #1828: ionosphere - mirage Redis data features However that ^^ is UNDESIRABLE in the Mirage/Ionosphere context at the moment. Ionosphere must only profile SECOND_ORDER_RESOLUTION_HOURS currently so as to not pollute the seasonality aspect of Mirage ''' # Create Ionosphere redis timeseries json if is does not exist # @modified 20161229 - Feature #1830: Ionosphere alerts # Only write the data to the file if it does not exist and replace # the timeseries object if a json file exists # @added 20170920 - Bug #2168: Strange Redis derivative graph using_original_redis_json = False if not os.path.isfile(json_file): timeseries_json = str(timeseries).replace('[', '(').replace( ']', ')') try: write_data_to_file(skyline_app, json_file, 'w', timeseries_json) logger.info( 'added %s Ionosphere Redis data timeseries json file :: %s' % (skyline_app, json_file)) except: logger.info(traceback.format_exc()) logger.error( 'error :: failed to add %s Ionosphere Redis data timeseries json file' % (skyline_app, json_file)) else: # Replace the timeseries object logger.info( '%s Ionosphere Redis data timeseries json file already exists, using :: %s' % (skyline_app, json_file)) anomaly_json = json_file try: # Read the timeseries json file with open(anomaly_json, 'r') as f: raw_timeseries = f.read() timeseries_array_str = str(raw_timeseries).replace( '(', '[').replace(')', ']') timeseries = literal_eval(timeseries_array_str) logger.info( '%s Redis timeseries replaced with timeseries from :: %s' % (skyline_app, anomaly_json)) timeseries_x = [float(item[0]) for item in timeseries] timeseries_y = [item[1] for item in timeseries] # @added 20170920 - Bug #2168: Strange Redis derivative graph # This already has nonNegativeDerivative applied to it using_original_redis_json = True except: logger.error(traceback.format_exc()) logger.error( 'error :: %s failed to read timeseries data from %s' % (skyline_app, anomaly_json)) timeseries = None # @added 20170603 - Feature #2034: analyse_derivatives if known_derivative_metric: # @added 20170920 - Bug #2168: Strange Redis derivative graph # If this is the Mirage Redis json it already has # nonNegativeDerivative applied to it if not using_original_redis_json: logger.info('alert_smtp - nonNegativeDerivative being applied') try: derivative_timeseries = nonNegativeDerivative(timeseries) timeseries = derivative_timeseries # @added 20170920 - Bug #2168: Strange Redis derivative graph logger.info('alert_smtp - nonNegativeDerivative applied') except: logger.error( 'error :: alert_smtp - nonNegativeDerivative failed') else: logger.info( 'alert_smtp - nonNegativeDerivative not being applied, as it will have been applied in the original json' ) # @added 21070726 - Bug #2068: Analyzer smtp alert error on Redis plot with derivative metrics # If the nonNegativeDerivative has been calculated we need to reset the # x and y as nonNegativeDerivative has to discard the first value as it # has no delta for it so the timeseries is 1 item less. timeseries_x = [float(item[0]) for item in timeseries] timeseries_y = [item[1] for item in timeseries] pd_series_values = None if timeseries: try: if LOCAL_DEBUG: logger.info( 'debug :: alert_smtp - Memory usage before pd.Series: %s (kb)' % resource.getrusage(resource.RUSAGE_SELF).ru_maxrss) values = pd.Series([x[1] for x in timeseries]) # Because the truth value of a Series is ambiguous pd_series_values = True if LOCAL_DEBUG: logger.info( 'debug :: alert_smtp - Memory usage after pd.Series: %s (kb)' % resource.getrusage(resource.RUSAGE_SELF).ru_maxrss) except: logger.error( 'error :: alert_smtp - pandas value series on timeseries failed' ) if pd_series_values: try: array_median = np.median(values) if settings.ENABLE_DEBUG or LOCAL_DEBUG: logger.info('debug :: alert_smtp - values median: %s' % str(array_median)) array_amax = np.amax(values) if settings.ENABLE_DEBUG or LOCAL_DEBUG: logger.info('debug :: alert_smtp - array_amax: %s' % str(array_amax)) array_amin = np.amin(values) if settings.ENABLE_DEBUG or LOCAL_DEBUG: logger.info('debug :: alert_smtp - array_amin: %s' % str(array_amin)) mean = values.mean() if settings.ENABLE_DEBUG or LOCAL_DEBUG: logger.info('debug :: alert_smtp - mean: %s' % str(mean)) stdDev = values.std() if settings.ENABLE_DEBUG or LOCAL_DEBUG: logger.info('debug :: alert_smtp - stdDev: %s' % str(stdDev)) sigma3 = 3 * stdDev if settings.ENABLE_DEBUG or LOCAL_DEBUG: logger.info('debug :: alert_smtp - sigma3: %s' % str(sigma3)) # sigma3_series = [sigma3] * len(values) sigma3_upper_bound = mean + sigma3 try: sigma3_lower_bound = mean - sigma3 except: sigma3_lower_bound = 0 sigma3_upper_series = [sigma3_upper_bound] * len(values) sigma3_lower_series = [sigma3_lower_bound] * len(values) amax_series = [array_amax] * len(values) amin_series = [array_amin] * len(values) mean_series = [mean] * len(values) except: logger.error( 'error :: alert_smtp - numpy ops on series failed') mean_series = None if mean_series: graph_title = 'Skyline %s - ALERT - at %s hours - Redis data\n%s - anomalous value: %s' % ( context, str( int(full_duration_in_hours)), metric[1], str(metric[0])) # @added 20170603 - Feature #2034: analyse_derivatives if known_derivative_metric: graph_title = 'Skyline %s - ALERT - at %s hours - Redis data (derivative graph)\n%s - anomalous value: %s' % ( context, str(int(full_duration_in_hours)), metric[1], str(metric[0])) # @modified 20160814 - Bug #1558: Memory leak in Analyzer # I think the buf is causing a memory leak, trying a file # if python_version == 3: # buf = io.StringIO() # else: # buf = io.BytesIO() buf = '%s/%s.%s.%s.png' % (settings.SKYLINE_TMP_DIR, skyline_app, str(int(metric[2])), metric[1]) if LOCAL_DEBUG: logger.info( 'debug :: alert_smtp - Memory usage before plot Redis data: %s (kb)' % resource.getrusage(resource.RUSAGE_SELF).ru_maxrss) # Too big # rcParams['figure.figsize'] = 12, 6 rcParams['figure.figsize'] = 8, 4 try: # fig = plt.figure() fig = plt.figure(frameon=False) ax = fig.add_subplot(111) ax.set_title(graph_title, fontsize='small') # @modified 20180417 - Bug #2358: set_axis_bgcolor method removed from Matplotlib - Luminosity # IssueID #49 'AxesSubplot' object has no attribute 'set_axis_bgcolor' # ax.set_axis_bgcolor('black') if hasattr(ax, 'set_facecolor'): ax.set_facecolor('black') else: ax.set_axis_bgcolor('black') try: datetimes = [ dt.datetime.utcfromtimestamp(ts) for ts in timeseries_x ] if settings.ENABLE_DEBUG or LOCAL_DEBUG: logger.info('debug :: alert_smtp - datetimes: %s' % 'OK') except: logger.error('error :: alert_smtp - datetimes: %s' % 'FAIL') plt.xticks(rotation=0, horizontalalignment='center') xfmt = DateFormatter('%a %H:%M') plt.gca().xaxis.set_major_formatter(xfmt) ax.xaxis.set_major_formatter(xfmt) ax.plot(datetimes, timeseries_y, color='orange', lw=0.6, zorder=3) ax.tick_params(axis='both', labelsize='xx-small') max_value_label = 'max - %s' % str(array_amax) ax.plot(datetimes, amax_series, lw=1, label=max_value_label, color='m', ls='--', zorder=4) min_value_label = 'min - %s' % str(array_amin) ax.plot(datetimes, amin_series, lw=1, label=min_value_label, color='b', ls='--', zorder=4) mean_value_label = 'mean - %s' % str(mean) ax.plot(datetimes, mean_series, lw=1.5, label=mean_value_label, color='g', ls='--', zorder=4) sigma3_text = (r'3$\sigma$') # sigma3_label = '%s - %s' % (str(sigma3_text), str(sigma3)) sigma3_upper_label = '%s upper - %s' % ( str(sigma3_text), str(sigma3_upper_bound)) ax.plot(datetimes, sigma3_upper_series, lw=1, label=sigma3_upper_label, color='r', ls='solid', zorder=4) if sigma3_lower_bound > 0: sigma3_lower_label = '%s lower - %s' % ( str(sigma3_text), str(sigma3_lower_bound)) ax.plot(datetimes, sigma3_lower_series, lw=1, label=sigma3_lower_label, color='r', ls='solid', zorder=4) ax.get_yaxis().get_major_formatter().set_useOffset(False) ax.get_yaxis().get_major_formatter().set_scientific(False) # Shrink current axis's height by 10% on the bottom box = ax.get_position() ax.set_position([ box.x0, box.y0 + box.height * 0.1, box.width, box.height * 0.9 ]) # Put a legend below current axis ax.legend(loc='upper center', bbox_to_anchor=(0.5, -0.05), fancybox=True, shadow=True, ncol=4, fontsize='x-small') plt.rc('lines', lw=2, color='w') plt.grid(True) ax.grid(b=True, which='both', axis='both', color='lightgray', linestyle='solid', alpha=0.5, linewidth=0.6) # @modified 20180417 - Bug #2358: set_axis_bgcolor method removed from Matplotlib - Luminosity # IssueID #49 'AxesSubplot' object has no attribute 'set_axis_bgcolor' # ax.set_axis_bgcolor('black') if hasattr(ax, 'set_facecolor'): ax.set_facecolor('black') else: ax.set_axis_bgcolor('black') rcParams['xtick.direction'] = 'out' rcParams['ytick.direction'] = 'out' ax.margins(y=.02, x=.03) # tight_layout removes the legend box # fig.tight_layout() try: if LOCAL_DEBUG: logger.info( 'debug :: alert_smtp - Memory usage before plt.savefig: %s (kb)' % resource.getrusage(resource.RUSAGE_SELF).ru_maxrss) plt.savefig(buf, format='png') if settings.IONOSPHERE_ENABLED: if not os.path.exists(training_data_dir): mkdir_p(training_data_dir) logger.info('created dir - %s' % training_data_dir) if not os.path.isfile(training_data_redis_image): try: plt.savefig(training_data_redis_image, format='png') logger.info( 'alert_smtp - save Redis training data image - %s' % (training_data_redis_image)) except: logger.info(traceback.format_exc()) logger.error( 'error :: alert_smtp - could not save - %s' % (training_data_redis_image)) else: logger.info( 'alert_smtp - Redis training data image already exists - %s' % (training_data_redis_image)) # @added 20160814 - Bug #1558: Memory leak in Analyzer # As per http://www.mail-archive.com/[email protected]/msg13222.html # savefig in the parent process was causing the memory leak # the below fig.clf() and plt.close() did not resolve this # however spawing a multiprocessing process for alert_smtp # does solve this as issue as all memory is freed when the # process terminates. fig.clf() plt.close(fig) redis_graph_content_id = 'redis.%s' % metric[1] redis_image_data = True if settings.ENABLE_DEBUG or LOCAL_DEBUG: logger.info('debug :: alert_smtp - savefig: %s' % 'OK') logger.info( 'debug :: alert_smtp - Memory usage after plt.savefig: %s (kb)' % resource.getrusage(resource.RUSAGE_SELF).ru_maxrss) except: logger.info(traceback.format_exc()) logger.error('error :: alert_smtp - plt.savefig: %s' % 'FAIL') except: logger.error(traceback.format_exc()) logger.error('error :: alert_smtp - could not build plot') if LOCAL_DEBUG: logger.info( 'debug :: alert_smtp - Memory usage before email: %s (kb)' % resource.getrusage(resource.RUSAGE_SELF).ru_maxrss) if redis_image_data: redis_img_tag = '<img src="cid:%s"/>' % redis_graph_content_id if settings.ENABLE_DEBUG or LOCAL_DEBUG: logger.info('debug :: alert_smtp - redis_img_tag: %s' % str(redis_img_tag)) else: # @modified 20161229 - Feature #1830: Ionosphere alerts # @modified 20170108 - Feature #1852: Ionosphere - features_profile matched graphite graphs # Restored the previous redis_img_tag method as some smtp alerts were # coming without a Redis graph, not all but some and for some reason, # I am pretty certain retrospectively that it was done that way from # testing I just wanted to try and be cleaner. # The redis_img_tag was changed at # https://github.com/earthgecko/skyline/commit/31bcacf3f90f0953ebed0d57260cb937e01f887c#diff-520bf2a218f65074ffead4d8184c138dR489 redis_img_tag = '<img src="%s"/>' % 'none' # redis_img_tag = '<img src="none"/>' # @added 20170806 - Feature #1830: Ionosphere alerts # Show a human date in alerts alerted_at = str(dt.datetime.utcfromtimestamp(int(metric[2]))) try: body = '<h3><font color="#dd3023">Sky</font><font color="#6698FF">line</font><font color="black"> %s alert</font></h3><br>' % context body += '<font color="black">metric: <b>%s</b></font><br>' % metric[1] body += '<font color="black">Anomalous value: %s</font><br>' % str( metric[0]) body += '<font color="black">Anomaly timestamp: %s</font><br>' % str( int(metric[2])) # @added 20170806 - Feature #1830: Ionosphere alerts # Show a human date in alerts body += '<font color="black">Anomalous at: %s</font><br>' % alerted_at body += '<font color="black">At hours: %s</font><br>' % str( int(full_duration_in_hours)) body += '<font color="black">Next alert in: %s seconds</font><br>' % str( alert[2]) # @added 20170603 - Feature #2034: analyse_derivatives if known_derivative_metric: body += '<font color="black">Derivative graph: True</font><br>' more_body = '' if settings.IONOSPHERE_ENABLED: # @modified 20170823 - Bug #2142: 7bit SMTP encoding breaking long urls # Broke body into body and more_body to workaround the 990 character # limit per line for SMTP more_body += '<h3><font color="#dd3023">Ionosphere :: </font><font color="#6698FF">training data</font><font color="black"></font></h3>' ionosphere_link = '%s/ionosphere?timestamp=%s&metric=%s' % ( settings.SKYLINE_URL, str(int(metric[2])), str(metric[1])) more_body += '<font color="black">To use this timeseries to train Skyline that this is not anomalous manage this training data at:<br>' more_body += '<a href="%s">%s</a></font>' % (ionosphere_link, ionosphere_link) if redis_image_data: more_body += '<font color="black">min: %s | max: %s | mean: %s <br>' % ( str(array_amin), str(array_amax), str(mean)) more_body += '3-sigma: %s <br>' % str(sigma3) more_body += '3-sigma upper bound: %s | 3-sigma lower bound: %s <br></font>' % ( str(sigma3_upper_bound), str(sigma3_lower_bound)) more_body += '<h3><font color="black">Redis data at FULL_DURATION</font></h3><br>' more_body += '<div dir="ltr">:%s<br></div>' % redis_img_tag if image_data: more_body += '<h3><font color="black">Graphite data at FULL_DURATION (may be aggregated)</font></h3>' more_body += '<div dir="ltr"><a href="%s">%s</a><br></div><br>' % ( link, img_tag) more_body += '<font color="black">Clicking on the above graph will open to the Graphite graph with current data</font><br>' if redis_image_data: more_body += '<font color="black">To disable the Redis data graph view, set PLOT_REDIS_DATA to False in your settings.py, if the Graphite graph is sufficient for you,<br>' more_body += 'however do note that will remove the 3-sigma and mean value too.</font>' more_body += '<br>' more_body += '<div dir="ltr" align="right"><font color="#dd3023">Sky</font><font color="#6698FF">line</font><font color="black"> version :: %s</font></div><br>' % str( skyline_version) except: logger.error('error :: alert_smtp - could not build body') logger.info(traceback.format_exc()) # @modified 20180524 - Task #2384: Change alerters to cc other recipients # Do not send to each recipient, send to primary_recipient and cc the other # recipients, thereby sending only one email # for recipient in recipients: if primary_recipient: try: # @modified 20170823 - Bug #2142: 7bit SMTP encoding breaking long urls # Broke body into body and more_body to workaround the 990 character # limit per line for SMTP, using mixed as alternative indicates that # the client should select one of the parts for display and ignore # the rest (tripleee - https://stackoverflow.com/a/35115938) # msg = MIMEMultipart('alternative') msg = MIMEMultipart('mixed') # @added 20170812 - Bug #2142: 7bit SMTP encoding breaking long urls # set email charset and email encodings cs_ = charset.Charset('utf-8') cs_.header_encoding = charset.QP cs_.body_encoding = charset.QP msg.set_charset(cs_) msg['Subject'] = '[Skyline alert] - %s ALERT - %s' % (context, metric[1]) msg['From'] = sender # @modified 20180524 - Task #2384: Change alerters to cc other recipients # msg['To'] = recipient msg['To'] = primary_recipient # @added 20180524 - Task #2384: Change alerters to cc other recipients # Added Cc if cc_recipients: msg['Cc'] = cc_recipients msg.attach(MIMEText(body, 'html')) # @added 20170823 - Bug #2142: 7bit SMTP encoding breaking long urls # Broke body into body and more_body to workaround the 990 character # limit per line for SMTP msg.replace_header('content-transfer-encoding', 'quoted-printable') msg.attach(MIMEText(more_body, 'html')) if redis_image_data: try: # @modified 20160814 - Bug #1558: Memory leak in Analyzer # I think the buf is causing a memory leak, trying a file # buf.seek(0) # msg_plot_attachment = MIMEImage(buf.read()) # msg_plot_attachment = MIMEImage(buf.read()) try: with open(buf, 'r') as f: plot_image_data = f.read() try: os.remove(buf) except OSError: logger.error( 'error :: alert_smtp - failed to remove file - %s' % buf) logger.info(traceback.format_exc()) pass except: logger.error('error :: failed to read plot file - %s' % buf) plot_image_data = None # @added 20161124 - Branch #922: ionosphere msg_plot_attachment = MIMEImage(plot_image_data) msg_plot_attachment.add_header( 'Content-ID', '<%s>' % redis_graph_content_id) msg.attach(msg_plot_attachment) if settings.ENABLE_DEBUG or LOCAL_DEBUG: logger.info( 'debug :: alert_smtp - msg_plot_attachment - redis data done' ) except: logger.error('error :: alert_smtp - msg_plot_attachment') logger.info(traceback.format_exc()) if image_data is not None: try: msg_attachment = MIMEImage(image_data) msg_attachment.add_header('Content-ID', '<%s>' % content_id) msg.attach(msg_attachment) if settings.ENABLE_DEBUG or LOCAL_DEBUG: logger.info( 'debug :: alert_smtp - msg_attachment - Graphite img source done' ) except: logger.error('error :: alert_smtp - msg_attachment') logger.info(traceback.format_exc()) except: logger.error('error :: alert_smtp - could not attach') logger.info(traceback.format_exc()) s = SMTP('127.0.0.1') try: # @modified 20180524 - Task #2384: Change alerters to cc other recipients # Send to primary_recipient and cc_recipients # s.sendmail(sender, recipient, msg.as_string()) if cc_recipients: s.sendmail(sender, [primary_recipient, cc_recipients], msg.as_string()) else: s.sendmail(sender, primary_recipient, msg.as_string()) if settings.ENABLE_DEBUG or LOCAL_DEBUG: # logger.info('debug :: alert_smtp - message sent to %s OK' % str(recipient)) logger.info( 'debug :: alert_smtp - message sent OK to primary_recipient :: %s, cc_recipients :: %s' % (str(primary_recipient), str(cc_recipients))) except: logger.info(traceback.format_exc()) # logger.error('error :: alert_smtp - could not send email to %s' % str(recipient)) logger.error( 'error :: alert_smtp - could not send email to primary_recipient :: %s, cc_recipients :: %s' % (str(primary_recipient), str(cc_recipients))) s.quit() if LOCAL_DEBUG: logger.info('debug :: alert_smtp - Memory usage after email: %s (kb)' % resource.getrusage(resource.RUSAGE_SELF).ru_maxrss) if redis_image_data: # buf.seek(0) # buf.write('none') if LOCAL_DEBUG: logger.info( 'debug :: alert_smtp - Memory usage before del redis_image_data objects: %s (kb)' % resource.getrusage(resource.RUSAGE_SELF).ru_maxrss) del raw_series del unpacker del timeseries[:] del timeseries_x[:] del timeseries_y[:] del values del datetimes[:] del msg_plot_attachment del redis_image_data # We del all variables that are floats as they become unique objects and # can result in what appears to be a memory leak, but is not, it is # just the way Python handles floats del mean del array_amin del array_amax del stdDev del sigma3 if LOCAL_DEBUG: logger.info( 'debug :: alert_smtp - Memory usage after del redis_image_data objects: %s (kb)' % resource.getrusage(resource.RUSAGE_SELF).ru_maxrss) if LOCAL_DEBUG: logger.info( 'debug :: alert_smtp - Memory usage before del fig object: %s (kb)' % resource.getrusage(resource.RUSAGE_SELF).ru_maxrss) # @added 20160814 - Bug #1558: Memory leak in Analyzer # Issue #21 Memory leak in Analyzer - https://github.com/earthgecko/skyline/issues/21 # As per http://www.mail-archive.com/[email protected]/msg13222.html fig.clf() plt.close(fig) del fig if LOCAL_DEBUG: logger.info( 'debug :: alert_smtp - Memory usage after del fig object: %s (kb)' % resource.getrusage(resource.RUSAGE_SELF).ru_maxrss) if LOCAL_DEBUG: logger.info( 'debug :: alert_smtp - Memory usage before del other objects: %s (kb)' % resource.getrusage(resource.RUSAGE_SELF).ru_maxrss) del recipients[:] del body del msg del image_data del msg_attachment if LOCAL_DEBUG: logger.info( 'debug :: alert_smtp - Memory usage after del other objects: %s (kb)' % resource.getrusage(resource.RUSAGE_SELF).ru_maxrss) return
# depending on which domain you are sending a e-mail to. from django.conf import settings from django.core.mail import SMTPConnection, SafeMIMEText, SafeMIMEMultipart, EmailMessage, make_msgid from django.utils.encoding import smart_unicode import re import unicodedata from email import charset from email.MIMEText import MIMEText from email.header import Header from email.utils import formatdate, parseaddr import mobilejpcodecs CHARSET_DOCOMO = charset.Charset('Shift_JIS') CHARSET_DOCOMO.header_encoding = charset.BASE64 CHARSET_DOCOMO.body_encoding = None CHARSET_DOCOMO.output_charset = 'Shift_JIS' CHARSET_DOCOMO.input_codec = 'x_sjis_docomo' CHARSET_DOCOMO.output_codec = 'x_sjis_docomo' CHARSET_KDDI = charset.Charset('Shift_JIS') CHARSET_KDDI.header_encoding = charset.BASE64 CHARSET_KDDI.body_encoding = None CHARSET_KDDI.output_charset = 'Shift_JIS' CHARSET_KDDI.input_codec = 'x_sjis_kddi' CHARSET_KDDI.output_codec = 'x_sjis_kddi' CHARSET_SOFTBANK = charset.Charset('utf-8') CHARSET_SOFTBANK.header_encoding = charset.BASE64
def __init__(self, payload, content): MIMENonMultipart.__init__(self, 'text', content, charset='utf-8') utf8qp = charset.Charset('utf-8') utf8qp.body_encoding = charset.QP self.set_payload(payload, charset=utf8qp)
from email import charset from email import header from email import message from email import utils from five import grok from tn.plonemailing import interfaces from zope.component import getMultiAdapter import os import quopri import random import re import time header_default_charset = charset.Charset('utf-8') header_default_charset.header_encoding = charset.QP domain_re = re.compile(r'.*@([^@]+)$') class BaseMessageFactory(object): def __init__(self, context, request, newsletter, subscriber): self.context = context self.request = request self.newsletter = newsletter self.subscriber = subscriber def __call__(self, content): msg = build_message_root(self.newsletter, self.subscriber) self._configure_message(msg, content) add_message_id(msg)
if is_lazy_string(val): val = val.value return to_unicode(val) # The following code is taken almost verbatim from `django.core.mail`, # which is licensed under the three-clause BSD license and is originally # available on the following URL: # https://github.com/django/django/tree/stable/1.11.x/django/core/mail/ # Credits of the original code go to the Django Software Foundation # and their contributors. # Don't BASE64-encode UTF-8 messages so that we avoid unwanted attention from # some spam filters. utf8_charset = Charset.Charset('utf-8') utf8_charset.body_encoding = None # Python defaults to BASE64 utf8_charset_qp = Charset.Charset('utf-8') utf8_charset_qp.body_encoding = Charset.QP # Default MIME type to use on attachments (if it is not explicitly given # and cannot be guessed). DEFAULT_ATTACHMENT_MIME_TYPE = 'application/octet-stream' RFC5322_EMAIL_LINE_LENGTH_LIMIT = 998 class BadHeaderError(ValueError): pass
def send_email(current_skyline_app, to, cc, subject, body, log=True): """ Send a plain text email. :param current_skyline_app: the app calling the function :param to: the to address :param cc: the cc addresses :param subject: the subject :param body: the body :type current_skyline_app: str :type to: str :type cc: list :type body: str :type log: boolean :return: sent :rtype: boolean """ function_str = 'functions.smtp.send_email' if log: current_skyline_app_logger = current_skyline_app + 'Log' current_logger = logging.getLogger(current_skyline_app_logger) else: current_logger = None sender = settings.SMTP_OPTS['sender'] primary_recipient = to cc_recipients = False recipients = [to] current_logger.info('%s - will send to primary_recipient :: %s, cc :: %s' % (function_str, str(primary_recipient), str(cc))) if len(cc) > 0: recipients = recipients + cc if recipients: for i_recipient in recipients: if not primary_recipient: primary_recipient = str(i_recipient) if primary_recipient != i_recipient: if not cc_recipients: cc_recipients = str(i_recipient) else: new_cc_recipients = '%s,%s' % (str(cc_recipients), str(i_recipient)) cc_recipients = str(new_cc_recipients) current_logger.info( '%s - will send to primary_recipient :: %s, cc_recipients :: %s' % (function_str, str(primary_recipient), str(cc_recipients))) send_email_alert = True if primary_recipient: try: msg = MIMEMultipart('mixed') cs_ = charset.Charset('utf-8') cs_.header_encoding = charset.QP cs_.body_encoding = charset.QP msg.set_charset(cs_) msg['Subject'] = str(subject) msg['From'] = sender msg['To'] = primary_recipient if cc_recipients: msg['Cc'] = cc_recipients html_body = '<h3><font color="#dd3023">Sky</font><font color="#6698FF">line</font><font color="black"></font></h3><br>' html_body += '%s' % str(body) # msg.attach(MIMEText(str(body), 'text')) msg.attach(MIMEText(html_body, 'html')) msg.replace_header('content-transfer-encoding', 'quoted-printable') if settings.DOCKER_FAKE_EMAIL_ALERTS: current_logger.info( 'alert_smtp - DOCKER_FAKE_EMAIL_ALERTS is set to %s, not executing SMTP command' % str(settings.DOCKER_FAKE_EMAIL_ALERTS)) send_email_alert = False except Exception as e: current_logger.error(traceback.format_exc()) current_logger.error( 'error :: %s :: could not send email to primary_recipient :: %s, cc_recipients :: %s - %s' % (str(function_str), str(primary_recipient), str(cc_recipients), e)) send_email_alert = False if send_email_alert: # @added 20220203 - Feature #4416: settings - additional SMTP_OPTS smtp_server = None try: smtp_server = determine_smtp_server() except Exception as err: current_logger.error(traceback.format_exc()) current_logger.error( 'error :: %s :: determine_smtp_server failed' % err) if not smtp_server: current_logger.error('error :: no smtp_server mail cannot be sent') return try: # @modified 20220203 - Feature #4416: settings - additional SMTP_OPTS # s = SMTP('127.0.0.1') if not smtp_server['ssl']: s = SMTP(smtp_server['host'], smtp_server['port']) else: s = SMTP_SSL(smtp_server['host'], smtp_server['port']) if smtp_server['user']: s.login(smtp_server['user'], smtp_server['password']) if cc_recipients: s.sendmail(sender, [primary_recipient, cc_recipients], msg.as_string()) else: s.sendmail(sender, primary_recipient, msg.as_string()) current_logger.info( '%s :: email sent - %s - primary_recipient :: %s, cc_recipients :: %s' % (str(function_str), subject, str(primary_recipient), str(cc_recipients))) except Exception as e: current_logger.error(traceback.format_exc()) current_logger.error( 'error :: %s :: could not send email to primary_recipient :: %s, cc_recipients :: %s - %s' % (str(function_str), str(primary_recipient), str(cc_recipients), e)) s.quit() else: current_logger.info( 'alert_smtp - send_email_alert was set to %s message was not sent to primary_recipient :: %s, cc_recipients :: %s' % (str(send_email_alert), str(primary_recipient), str(cc_recipients))) return
from ..lib.utils import waiting_get from ..lib.sqla import DuplicateHandling from ..lib import config from .auth import (User, Everyone, P_ADMIN_DISC, CrudPermissions, P_READ) from .permissions import UserTemplate from .discussion import Discussion from .generic import Content from .post import Post, SynthesisPost, PublicationStates from assembl.semantic.virtuoso_mapping import QuadMapPatternS from assembl.semantic.namespaces import ASSEMBL _ = TranslationStringFactory('assembl') # Don't BASE64-encode UTF-8 messages so that we avoid unwanted attention from # some spam filters. utf8_charset = Charset.Charset('utf-8') utf8_charset.body_encoding = None # Python defaults to BASE64 class SafeMIMEText(MIMEText): def __init__(self, text, subtype, charset): self.encoding = charset if charset == 'utf-8': # Unfortunately, Python < 3.5 doesn't support setting a Charset instance # as MIMEText init parameter (http://bugs.python.org/issue16324). # We do it manually and trigger re-encoding of the payload. MIMEText.__init__(self, text, subtype, None) del self['Content-Transfer-Encoding'] self.set_payload(text, utf8_charset) self.replace_header('Content-Type', 'text/%s; charset="%s"' % (subtype, charset))
os.umask(old_umask) os.chown(file_dir, *chowner) old_umask = None if config.get('permissions'): old_umask = os.umask(file_mask) with open(filename, 'w') as fd: output('writing file %s' % (filename,)) fd.write(config.get('contents', '')) if old_umask is not None: os.umask(old_umask) os.chown(filename, *chowner) """ # Avoid base64 encoding the MIME parts UTF8_CHARSET = charset.Charset('utf-8') UTF8_CHARSET.body_encoding = None # Python defaults to BASE64 def _new_mime_part(container, content_type, payload): # MIMEText will prepend to the content_type content_type = re.sub(r'^text/', '', content_type) message = MIMEText(payload, content_type, 'utf-8') del message['Content-Transfer-Encoding'] message.set_payload(payload, UTF8_CHARSET) container.attach(message) def get_mime_part_payload(mime_data, part_content_type): """ Return the payload for the part with the specified content-type.