From ee1c499467c2c973b088beb4ddbc58e8c7cbf8ed Mon Sep 17 00:00:00 2001 From: Anand Date: Sat, 15 Dec 2007 11:48:20 +0530 Subject: [PATCH] New functions: sendmail, emailerrors (pulled from webpy.dev) --- trunk/web/debugerror.py | 48 ++++++++++++++++++++++++++++++++++++++--- trunk/web/net.py | 2 -- trunk/web/utils.py | 32 +++++++++++++++++++++++++-- 3 files changed, 75 insertions(+), 7 deletions(-) diff --git a/trunk/web/debugerror.py b/trunk/web/debugerror.py index 1de465a8..a84f23c1 100644 --- a/trunk/web/debugerror.py +++ b/trunk/web/debugerror.py @@ -2,17 +2,18 @@ pretty debug errors (part of web.py) -adapted from Django +portions adapted from Django Copyright (c) 2005, the Lawrence Journal-World Used under the modified BSD license: http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5 """ -__all__ = ["debugerror", "djangoerror"] +__all__ = ["debugerror", "djangoerror", "emailerrors"] -import sys, urlparse, pprint +import sys, urlparse, pprint, traceback from net import websafe from template import Template +from utils import sendmail import webapi as web import os, os.path @@ -303,6 +304,47 @@ def debugerror(): web.ctx.headers = [('Content-Type', 'text/html')] web.ctx.output = djangoerror() +def emailerrors(email_address, olderror): + """ + Wraps the old `internalerror` handler (pass as `olderror`) to + additionally email all errors to `email_address`, to aid in + debugging production websites. + + Emails contain a normal text traceback as well as an + attachment containing the nice `debugerror` page. + """ + def emailerrors_internal(): + olderror() + tb = sys.exc_info() + error_name = tb[0] + error_value = tb[1] + tb_txt = ''.join(traceback.format_exception(*tb)) + path = web.ctx.path + request = web.ctx.method+' '+web.ctx.home+web.ctx.fullpath + eaddr = email_address + text = ("""\ +From: your buggy site <%(eaddr)s> +To: the bugfixer <%(eaddr)s> +Subject: bug: %(error_name)s: %(error_value)s (%(path)s) +Content-Type: multipart/mixed; boundary="----here----" + +------here---- +Content-Type: text/plain +Content-Disposition: inline + +%(request)s + +%(tb_txt)s + +------here---- +Content-Type: text/html; name="bug.html" +Content-Disposition: attachment; filename="bug.html" + +""" % locals()) + str(djangoerror()) + sendmail(email_address, email_address, text) + + return emailerrors_internal + if __name__ == "__main__": urls = ( '/', 'index' diff --git a/trunk/web/net.py b/trunk/web/net.py index 55a41b4d..1e6bb8a8 100644 --- a/trunk/web/net.py +++ b/trunk/web/net.py @@ -146,8 +146,6 @@ def htmlunquote(text): text = text.replace("&", "&") # Must be done last! return text - - def websafe(val): """ Converts `val` so that it's safe for use in UTF-8 HTML. diff --git a/trunk/web/utils.py b/trunk/web/utils.py index 6802ac37..45003551 100644 --- a/trunk/web/utils.py +++ b/trunk/web/utils.py @@ -20,10 +20,11 @@ "ThreadedDict", "autoassign", "to36", - "safemarkdown" + "safemarkdown", + "sendmail" ] -import re, sys, time, threading +import re, sys, time, threading, os try: import datetime except ImportError: pass @@ -790,6 +791,33 @@ def safemarkdown(text): text = markdown(text) return text +def sendmail(from_address, to_address, message): + """ + Sends the email message `message` to `to_address` with the + envelope sender set to `from_address`. + + If `web.config.smtp_server` is set, it will send the message + to that SMTP server. Otherwise it will look for + `/usr/lib/sendmail`, the typical location for the sendmail-style + binary. + """ + try: + import webapi + except ImportError: + webapi = Storage(config=storage()) + + if webapi.config.get('smtp_server'): + import smtplib + smtpserver = smtplib.SMTP(web.config.smtp_server) + smtpserver.sendmail(from_address, [to_address], message) + smtpserver.quit() + else: + assert not from_address.startswith('-') and not to_address.startswith('-'), 'security' + i, o = os.popen2(["/usr/lib/sendmail", '-f', from_address, to_address]) + i.write(message) + i.close() + o.close() + del i, o if __name__ == "__main__": import doctest