diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py
index 13f7991..40a5ca4 100644
--- a/django/conf/global_settings.py
+++ b/django/conf/global_settings.py
@@ -197,6 +197,7 @@ TEMPLATE_LOADERS = (
 # only parameter and returns a dictionary to add to the context.
 TEMPLATE_CONTEXT_PROCESSORS = (
     'django.contrib.auth.context_processors.auth',
+    'django.contrib.sites.context_processors.site',
     'django.core.context_processors.debug',
     'django.core.context_processors.i18n',
     'django.core.context_processors.media',
diff --git a/django/contrib/auth/views.py b/django/contrib/auth/views.py
index c86ef53..7d1fbc3 100644
--- a/django/contrib/auth/views.py
+++ b/django/contrib/auth/views.py
@@ -62,7 +62,6 @@ def login(request, template_name='registration/login.html',
     context = {
         'form': form,
         redirect_field_name: redirect_to,
-        'site': current_site,
         'site_name': current_site.name,
     }
     if extra_context is not None:
diff --git a/django/contrib/sites/context_processors.py b/django/contrib/sites/context_processors.py
new file mode 100644
index 0000000..0922dd3
--- /dev/null
+++ b/django/contrib/sites/context_processors.py
@@ -0,0 +1,17 @@
+from django.contrib.sites.models import Site, RequestSite
+from django.core.exceptions import ImproperlyConfigured
+from django.db import models
+
+
+def site(request):
+    """Sets in the present context information about the current site."""
+
+    # Current SiteManager already handles prevention of spurious
+    # database calls. If the user does not have the Sites framework
+    # installed, a RequestSite object is an appropriate fallback.
+    try:
+        site_app = models.get_app('sites')
+        site_obj = Site.objects.get_current()
+    except ImproperlyConfigured:
+        site_obj = RequestSite(request)
+    return {'site': site_obj}
diff --git a/django/contrib/sites/tests/__init__.py b/django/contrib/sites/tests/__init__.py
new file mode 100644
index 0000000..580a75f
--- /dev/null
+++ b/django/contrib/sites/tests/__init__.py
@@ -0,0 +1,2 @@
+from django.contrib.sites.tests.base import SitesFrameworkTests
+from django.contrib.sites.tests.context_processors import ContextProcessorTest
diff --git a/django/contrib/sites/tests/base.py b/django/contrib/sites/tests/base.py
new file mode 100644
index 0000000..da21b7b
--- /dev/null
+++ b/django/contrib/sites/tests/base.py
@@ -0,0 +1,66 @@
+from django.conf import settings
+
+from django.contrib.sites.models import Site, RequestSite, get_current_site
+from django.core.exceptions import ObjectDoesNotExist
+from django.http import HttpRequest
+from django.test import TestCase
+
+
+class SitesFrameworkTests(TestCase):
+
+    def setUp(self):
+        Site(id=settings.SITE_ID,
+             domain="example.com",
+             name="example.com").save()
+        self.old_Site_meta_installed = Site._meta.installed
+        Site._meta.installed = True
+
+    def tearDown(self):
+        Site._meta.installed = self.old_Site_meta_installed
+
+    def test_save_another(self):
+        # Regression for #17415.
+        # On some backends the sequence needs reset after save with
+        # explicit ID.  Test that there is no sequence collisions by
+        # saving another site.
+        Site(domain="example2.com", name="example2.com").save()
+
+    def test_site_manager(self):
+        # Make sure that get_current() does not return a deleted Site object.
+        s = Site.objects.get_current()
+        self.assertTrue(isinstance(s, Site))
+        s.delete()
+        self.assertRaises(ObjectDoesNotExist, Site.objects.get_current)
+
+    def test_site_cache(self):
+        # After updating a Site object (e.g. via the admin), we
+        # shouldn't return a bogus value from the SITE_CACHE.
+        site = Site.objects.get_current()
+        self.assertEqual(u"example.com", site.name)
+        s2 = Site.objects.get(id=settings.SITE_ID)
+        s2.name = "Example site"
+        s2.save()
+        site = Site.objects.get_current()
+        self.assertEqual(u"Example site", site.name)
+
+    def test_get_current_site(self):
+        # Test that the correct Site object is returned
+        request = HttpRequest()
+        request.META = {
+            "SERVER_NAME": "example.com",
+            "SERVER_PORT": "80",
+        }
+        site = get_current_site(request)
+        self.assertTrue(isinstance(site, Site))
+        self.assertEqual(site.id, settings.SITE_ID)
+
+        # Test that an exception is raised if the sites framework is installed
+        # but there is no matching Site
+        site.delete()
+        self.assertRaises(ObjectDoesNotExist, get_current_site, request)
+
+        # A RequestSite is returned if the sites framework is not installed
+        Site._meta.installed = False
+        site = get_current_site(request)
+        self.assertTrue(isinstance(site, RequestSite))
+        self.assertEqual(site.name, u"example.com")
diff --git a/django/contrib/sites/tests/context_processors.py b/django/contrib/sites/tests/context_processors.py
new file mode 100644
index 0000000..d5c5aa8
--- /dev/null
+++ b/django/contrib/sites/tests/context_processors.py
@@ -0,0 +1,35 @@
+#-*- coding:utf-8 -*-
+
+import os
+
+from django.conf import settings
+from django.contrib.sites.models import Site, RequestSite
+from django.test import TestCase
+from django.test.client import RequestFactory
+from django.test.utils import override_settings
+
+
+template_directory = os.path.join(os.path.dirname(__file__), 'templates')
+
+
+@override_settings(TEMPLATE_DIRS=(template_directory,))
+class ContextProcessorTest(TestCase):
+    urls = 'django.contrib.sites.tests.urls'
+
+    def test_context_processor(self):
+        response = self.client.get('/context_processors/')
+        site_obj = Site.objects.get_current()
+        self.assertEqual(response.status_code, 200)
+        self.assertContains(response, 'site.name: %s' % site_obj.name)
+        self.assertContains(response, 'site.domain: %s' % site_obj.domain)
+
+    def test_context_processor_without_sites_framework(self):
+        server_url = 'test.example.com'
+        apps = list(settings.INSTALLED_APPS)
+        apps.remove('django.contrib.sites')
+        with self.settings(INSTALLED_APPS=apps):
+            response = self.client.get('/context_processors/',
+                                       SERVER_NAME=server_url)
+        self.assertEqual(response.status_code, 200)
+        self.assertContains(response, 'site.name: %s' % server_url)
+        self.assertContains(response, 'site.domain: %s' % server_url)
diff --git a/django/contrib/sites/tests/templates/sites/context_processors_test.html b/django/contrib/sites/tests/templates/sites/context_processors_test.html
new file mode 100644
index 0000000..a2e2ee8
--- /dev/null
+++ b/django/contrib/sites/tests/templates/sites/context_processors_test.html
@@ -0,0 +1,2 @@
+site.name: {{ site.name }}
+site.domain: {{ site.domain }}
diff --git a/django/contrib/sites/tests/urls.py b/django/contrib/sites/tests/urls.py
new file mode 100644
index 0000000..7d16667
--- /dev/null
+++ b/django/contrib/sites/tests/urls.py
@@ -0,0 +1,7 @@
+from django.conf.urls import patterns
+from django.views.generic import TemplateView
+
+urlpatterns = patterns('',
+    (r'^context_processors/$',
+     TemplateView.as_view(
+       template_name='sites/context_processors_test.html')),)
diff --git a/django/contrib/syndication/views.py b/django/contrib/syndication/views.py
index af767e1..6ddd8ed 100644
--- a/django/contrib/syndication/views.py
+++ b/django/contrib/syndication/views.py
@@ -139,11 +139,13 @@ class Feed(object):
 
         for item in self.__get_dynamic_attr('items', obj):
             if title_tmp is not None:
-                title = title_tmp.render(RequestContext(request, {'obj': item, 'site': current_site}))
+                title = title_tmp.render( \
+                  RequestContext(request, {'obj': item}))
             else:
                 title = self.__get_dynamic_attr('item_title', item)
             if description_tmp is not None:
-                description = description_tmp.render(RequestContext(request, {'obj': item, 'site': current_site}))
+                description = description_tmp.render( \
+                  RequestContext(request, {'obj': item}))
             else:
                 description = self.__get_dynamic_attr('item_description', item)
             link = add_domain(
diff --git a/django/views/generic/__init__.py b/django/views/generic/__init__.py
index 1a98067..2c51513 100644
--- a/django/views/generic/__init__.py
+++ b/django/views/generic/__init__.py
@@ -1,9 +1,11 @@
 from django.views.generic.base import View, TemplateView, RedirectView
-from django.views.generic.dates import (ArchiveIndexView, YearArchiveView, MonthArchiveView,
-                                     WeekArchiveView, DayArchiveView, TodayArchiveView,
-                                     DateDetailView)
+from django.views.generic.dates import (ArchiveIndexView, YearArchiveView,
+                                        MonthArchiveView, WeekArchiveView,
+                                        DayArchiveView, TodayArchiveView,
+                                        DateDetailView)
 from django.views.generic.detail import DetailView
-from django.views.generic.edit import FormView, CreateView, UpdateView, DeleteView
+from django.views.generic.edit import (FormView, CreateView,
+                                       UpdateView, DeleteView)
 from django.views.generic.list import ListView
 
 
diff --git a/docs/ref/contrib/sites.txt b/docs/ref/contrib/sites.txt
index 8fc434b..d9587c7 100644
--- a/docs/ref/contrib/sites.txt
+++ b/docs/ref/contrib/sites.txt
@@ -174,7 +174,7 @@ fallback for cases where it is not installed.
 .. function:: get_current_site(request)
 
     Checks if contrib.sites is installed and returns either the current
-    :class:`~django.contrib.sites.models.Site` object or a 
+    :class:`~django.contrib.sites.models.Site` object or a
     :class:`~django.contrib.sites.models.RequestSite` object based on
     the request.
 
@@ -215,26 +215,32 @@ On Lawrence.com, this email has the subject line "Thanks for subscribing to
 lawrence.com alerts." On LJWorld.com, the email has the subject "Thanks for
 subscribing to LJWorld.com alerts." Same goes for the email's message body.
 
-Note that an even more flexible (but more heavyweight) way of doing this would
-be to use Django's template system. Assuming Lawrence.com and LJWorld.com have
-different template directories (:setting:`TEMPLATE_DIRS`), you could simply farm out
-to the template system like so::
+The current Site object is made available in the
+:doc:`template context </ref/templates/api>` when you use
+:class:`~django.template.RequestContext` and when your
+:setting:`TEMPLATE_CONTEXT_PROCESSORS` setting contains
+``'django.contrib.sites.context_processors.site'``, which is default.
+
+Using template context, an even more flexible way of sending
+email-notifications would be to use Django's template system::
 
     from django.core.mail import send_mail
-    from django.template import loader, Context
+    from django.template import loader, RequestContext
 
     def register_for_newsletter(request):
         # Check form values, etc., and subscribe the user.
         # ...
 
-        subject = loader.get_template('alerts/subject.txt').render(Context({}))
-        message = loader.get_template('alerts/message.txt').render(Context({}))
+        subject_template = loader.get_template('alerts/subject.txt')
+        subject = subject_template.render(RequestContext(request, {}))
+        message_template = loader.get_template('alerts/message.txt')
+        message = message_template.render(RequestContext(request, {}))
         send_mail(subject, message, 'editor@ljworld.com', [user.email])
 
         # ...
 
 In this case, you'd have to create :file:`subject.txt` and :file:`message.txt` template
-files for both the LJWorld.com and Lawrence.com template directories. That
+files that include ``{{ site.name }}`` and ``{{ site.domain }}``. That
 gives you more flexibility, but it's also more complex.
 
 It's a good idea to exploit the :class:`~django.contrib.sites.models.Site`
@@ -389,10 +395,7 @@ Here's how Django uses the sites framework:
   checks the current :setting:`SITE_ID` in retrieving flatpages to display.
 
 * In the :mod:`syndication framework <django.contrib.syndication>`, the
-  templates for ``title`` and ``description`` automatically have access to a
-  variable ``{{ site }}``, which is the
-  :class:`~django.contrib.sites.models.Site` object representing the current
-  site. Also, the hook for providing item URLs will use the ``domain`` from
+  hook for providing item URLs will use the ``domain`` from
   the current :class:`~django.contrib.sites.models.Site` object if you don't
   specify a fully-qualified domain.
 
@@ -437,7 +440,7 @@ fallback when the database-backed sites framework is not available.
 
         Sets the ``name`` and ``domain`` attributes to the value of
         :meth:`~django.http.HttpRequest.get_host`.
-        
+
 
 A :class:`~django.contrib.sites.models.RequestSite` object has a similar
 interface to a normal :class:`~django.contrib.sites.models.Site` object, except
diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt
index 627aa50..cc8f117 100644
--- a/docs/ref/settings.txt
+++ b/docs/ref/settings.txt
@@ -1880,6 +1880,7 @@ TEMPLATE_CONTEXT_PROCESSORS
 Default::
 
     ("django.contrib.auth.context_processors.auth",
+    "django.contrib.sites.context_processors.site",
     "django.core.context_processors.debug",
     "django.core.context_processors.i18n",
     "django.core.context_processors.media",
@@ -1899,6 +1900,10 @@ of items to be merged into the context.
     The ``django.core.context_processors.tz`` context processor
     was added in this release.
 
+.. versionadded:: 1.5
+    The ``django.contrib.sites.context_processors.site`` context
+    processor was added in this release.
+
 .. setting:: TEMPLATE_DEBUG
 
 TEMPLATE_DEBUG
