diff --git a/django/core/mail/__init__.py b/django/core/mail/__init__.py index 8d064223cd9..a3ad837bc9e 100644 --- a/django/core/mail/__init__.py +++ b/django/core/mail/__init__.py @@ -83,22 +83,30 @@ def send_mass_mail(datatuple, fail_silently=False, auth_user=None, return connection.send_messages(messages) -def mail_admins(subject, message, fail_silently=False, connection=None): +def mail_admins(subject, message, fail_silently=False, connection=None, + html_message=None): """Sends a message to the admins, as defined by the ADMINS setting.""" if not settings.ADMINS: return - EmailMessage(u'%s%s' % (settings.EMAIL_SUBJECT_PREFIX, subject), message, - settings.SERVER_EMAIL, [a[1] for a in settings.ADMINS], - connection=connection).send(fail_silently=fail_silently) + mail = EmailMultiAlternatives(u'%s%s' % (settings.EMAIL_SUBJECT_PREFIX, subject), + message, settings.SERVER_EMAIL, [a[1] for a in settings.ADMINS], + connection=connection) + if html_message: + mail.attach_alternative(html_message, 'text/html') + mail.send(fail_silently=fail_silently) -def mail_managers(subject, message, fail_silently=False, connection=None): +def mail_managers(subject, message, fail_silently=False, connection=None, + html_message=None): """Sends a message to the managers, as defined by the MANAGERS setting.""" if not settings.MANAGERS: return - EmailMessage(u'%s%s' % (settings.EMAIL_SUBJECT_PREFIX, subject), message, - settings.SERVER_EMAIL, [a[1] for a in settings.MANAGERS], - connection=connection).send(fail_silently=fail_silently) + mail = EmailMultiAlternatives(u'%s%s' % (settings.EMAIL_SUBJECT_PREFIX, subject), + message, settings.SERVER_EMAIL, [a[1] for a in settings.MANAGERS], + connection=connection) + if html_message: + mail.attach_alternative(html_message, 'text/html') + mail.send(fail_silently=fail_silently) class SMTPConnection(_SMTPConnection): diff --git a/django/utils/log.py b/django/utils/log.py index b9d32e339b2..d3c8e67a307 100644 --- a/django/utils/log.py +++ b/django/utils/log.py @@ -56,6 +56,7 @@ class AdminEmailHandler(logging.Handler): def emit(self, record): import traceback from django.conf import settings + from django.views.debug import ExceptionReporter try: if sys.version_info < (2,5): @@ -75,12 +76,18 @@ class AdminEmailHandler(logging.Handler): request_repr = repr(request) except: subject = 'Error: Unknown URL' + request = None request_repr = "Request repr() unavailable" if record.exc_info: + exc_info = record.exc_info stack_trace = '\n'.join(traceback.format_exception(*record.exc_info)) else: + exc_info = () stack_trace = 'No stack trace available' message = "%s\n\n%s" % (stack_trace, request_repr) - mail.mail_admins(subject, message, fail_silently=True) + reporter = ExceptionReporter(request, *exc_info, is_email=True) + html_message = reporter.get_traceback_html() + mail.mail_admins(subject, message, fail_silently=True, + html_message=html_message) diff --git a/django/views/debug.py b/django/views/debug.py index 7050ea38fb6..5c75a49e9ac 100644 --- a/django/views/debug.py +++ b/django/views/debug.py @@ -62,11 +62,12 @@ class ExceptionReporter: """ A class to organize and coordinate reporting on exceptions. """ - def __init__(self, request, exc_type, exc_value, tb): + def __init__(self, request, exc_type, exc_value, tb, is_email=False): self.request = request self.exc_type = exc_type self.exc_value = exc_value self.tb = tb + self.is_email = is_email self.template_info = None self.template_does_not_exist = False @@ -118,6 +119,7 @@ class ExceptionReporter: from django import get_version t = Template(TECHNICAL_500_TEMPLATE, name='Technical 500 template') c = Context({ + 'is_email': self.is_email, 'exception_type': self.exc_type.__name__, 'exception_value': smart_unicode(self.exc_value, errors='replace'), 'unicode_hint': unicode_hint, @@ -324,7 +326,7 @@ TECHNICAL_500_TEMPLATE = """ table.vars { margin:5px 0 2px 40px; } table.vars td, table.req td { font-family:monospace; } table td.code { width:100%; } - table td.code div { overflow:hidden; } + table td.code pre { overflow:hidden; } table.source th { color:#666; } table.source td { font-family:monospace; white-space:pre; border-bottom:1px solid #eee; } ul.traceback { list-style-type:none; } @@ -353,6 +355,7 @@ TECHNICAL_500_TEMPLATE = """ span.commands a:link {color:#5E5694;} pre.exception_value { font-family: sans-serif; color: #666; font-size: 1.5em; margin: 10px 0 10px 0; } + {% if not is_email %} + {% endif %}
{{ exception_value|force_escape }}
Python Path: | -{{ sys_path }} | +{{ sys_path|pprint }} |
|||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Server time: | @@ -498,7 +502,7 @@ TECHNICAL_500_TEMPLATE = """ {% endif %}
{{ var.0|force_escape }} | -{{ var.1|pprint|force_escape }} |
+ {{ var.1|pprint|force_escape }} |
{{ var.0 }} | -{{ var.1|pprint }} |
+ {{ var.1|pprint }} |
{{ var.0 }} | -{{ var.1|pprint }} |
+ {{ var.1|pprint }} |
{{ var.0 }} | -{{ var.1|pprint }} |
+ {{ var.1|pprint }} |
{{ var.0 }} | -{{ var.1|pprint }} |
+ {{ var.1|pprint }} |
{{ var.0 }} | -{{ var.1|pprint }} |
+ {{ var.1|pprint }} |
{{ settings.SETTINGS_MODULE }}
{{ var.1|pprint }}