diff --git a/opentech/apply/dashboard/templates/dashboard/dashboard.html b/opentech/apply/dashboard/templates/dashboard/dashboard.html
index d467da86e95e7e625d96e9ac200dd665ce101eff..73fead516f52b250612d4e7706efe9dee2e00f93 100644
--- a/opentech/apply/dashboard/templates/dashboard/dashboard.html
+++ b/opentech/apply/dashboard/templates/dashboard/dashboard.html
@@ -5,10 +5,13 @@
 
 {% block content %}
 <div class="admin-bar">
-    <div class="admin-bar__inner">
+    <div class="admin-bar__inner admin-bar__inner--with-button">
         {% block page_header %}
             <h1 class="gamma heading heading--no-margin heading--bold">Dashboard</h1>
         {% endblock %}
+        <a href="{% url 'wagtailadmin_home' %}" class="button button--primary {{ class }}}">
+            Apply admin
+        </a>
     </div>
 </div>
 <div class="wrapper wrapper--large wrapper--inner-space-medium">
diff --git a/opentech/apply/dashboard/wagtail_hooks.py b/opentech/apply/dashboard/wagtail_hooks.py
new file mode 100644
index 0000000000000000000000000000000000000000..89843e82ecd19e03272655582f5599b014b02753
--- /dev/null
+++ b/opentech/apply/dashboard/wagtail_hooks.py
@@ -0,0 +1,19 @@
+from urllib.parse import urljoin
+
+from django.urls import reverse
+
+from wagtail.core import hooks
+from wagtail.admin.menu import MenuItem
+
+from opentech.apply.home.models import ApplyHomePage
+
+
+@hooks.register('register_admin_menu_item')
+def register_dashboard_menu_item():
+    apply_home = ApplyHomePage.objects.first()
+    return MenuItem(
+        'Apply Dashboard',
+        urljoin(apply_home.url, reverse('dashboard:dashboard', 'opentech.apply.urls')),
+        classnames='icon icon-arrow-left',
+        order=100000,
+    )
diff --git a/opentech/apply/determinations/tests/test_views.py b/opentech/apply/determinations/tests/test_views.py
index 5f3f0c00523e6d466094e84bd86924ac5d4e2af2..b5d8f49823dc05300e77ebbc06123f79a183ff9d 100644
--- a/opentech/apply/determinations/tests/test_views.py
+++ b/opentech/apply/determinations/tests/test_views.py
@@ -1,42 +1,18 @@
-from django.test import TestCase, RequestFactory
 from django.urls import reverse
 
 from opentech.apply.activity.models import Activity
 from opentech.apply.determinations.models import ACCEPTED
 from opentech.apply.users.tests.factories import StaffFactory, UserFactory
 from opentech.apply.funds.tests.factories import ApplicationSubmissionFactory
+from opentech.apply.utils.testing import BaseViewTestCase
 
 from .factories import DeterminationFactory
 
 
-class BaseTestCase(TestCase):
-    url_name = ''
-    user_factory = None
-
-    def setUp(self):
-        self.factory = RequestFactory()
-        self.user = self.user_factory()
-        self.client.force_login(self.user)
-
-    def url(self, instance, view_name='detail'):
-        full_url_name = self.url_name.format(view_name)
-        url = reverse(full_url_name, kwargs=self.get_kwargs(instance))
-        request = self.factory.get(url, secure=True)
-        return request.build_absolute_uri()
-
-    def get_page(self, instance, view_name='detail'):
-        return self.client.get(self.url(instance, view_name), secure=True, follow=True)
-
-    def post_page(self, instance, data, view_name='detail'):
-        return self.client.post(self.url(instance, view_name), data, secure=True, follow=True)
-
-    def refresh(self, instance):
-        return instance.__class__.objects.get(id=instance.id)
-
-
-class StaffDeterminationsTestCase(BaseTestCase):
+class StaffDeterminationsTestCase(BaseViewTestCase):
     user_factory = StaffFactory
     url_name = 'funds:submissions:determinations:{}'
+    base_view_name = 'detail'
 
     def get_kwargs(self, instance):
         return {'submission_pk': instance.submission.id}
@@ -60,9 +36,10 @@ class StaffDeterminationsTestCase(BaseTestCase):
         self.assertTrue(response.context['can_view_extended_data'])
 
 
-class DeterminationFormTestCase(BaseTestCase):
+class DeterminationFormTestCase(BaseViewTestCase):
     user_factory = StaffFactory
     url_name = 'funds:submissions:determinations:{}'
+    base_view_name = 'detail'
 
     def get_kwargs(self, instance):
         return {'submission_pk': instance.id}
@@ -141,9 +118,10 @@ class DeterminationFormTestCase(BaseTestCase):
         self.assertEqual(submission_next.status, 'draft_proposal')
 
 
-class UserDeterminationFormTestCase(BaseTestCase):
+class UserDeterminationFormTestCase(BaseViewTestCase):
     user_factory = UserFactory
     url_name = 'funds:submissions:determinations:{}'
+    base_view_name = 'detail'
 
     def get_kwargs(self, instance):
         return {'submission_pk': instance.id}
diff --git a/opentech/apply/funds/templates/funds/includes/field.html b/opentech/apply/funds/templates/funds/includes/field.html
index 51c02144e836570e2240c8a97d35aff4450a9cdb..b4e71892f1d7cc7f63fccb07dd72363ff7dc6c49 100644
--- a/opentech/apply/funds/templates/funds/includes/field.html
+++ b/opentech/apply/funds/templates/funds/includes/field.html
@@ -21,7 +21,7 @@
     {% endif %}
 
     {% if field.help_text %}
-        <p class="form__help">{{ field.help_text }}</p>
+        <p class="form__help">{{ field.help_text|safe }}</p>
     {% endif %}
 
     <div class="form__item">
diff --git a/opentech/apply/funds/tests/factories/models.py b/opentech/apply/funds/tests/factories/models.py
index 05e972613c8e43636b4cfad614a334589f68c2e9..286c340cd1fd4a05721107d15625c0a5aa5ec4cc 100644
--- a/opentech/apply/funds/tests/factories/models.py
+++ b/opentech/apply/funds/tests/factories/models.py
@@ -21,6 +21,7 @@ from opentech.apply.funds.models.forms import (
 )
 from opentech.apply.users.tests.factories import StaffFactory, UserFactory
 from opentech.apply.stream_forms.testing.factories import FormDataFactory
+from opentech.apply.home.factories import ApplyHomePageFactory
 
 from . import blocks
 
@@ -35,6 +36,7 @@ __all__ = [
     'RoundBaseFormFactory',
     'LabFactory',
     'LabBaseFormFactory',
+    'LabSubmissionFactory',
     'SealedRoundFactory',
     'SealedSubmissionFactory',
 ]
@@ -69,6 +71,21 @@ class FundTypeFactory(wagtail_factories.PageFactory):
     # Will need to update how the stages are identified as Fund Page changes
     workflow_name = factory.LazyAttribute(lambda o: list(FundType.WORKFLOW_CHOICES.keys())[o.workflow_stages - 1])
 
+    @factory.post_generation
+    def parent(self, create, extracted_parent, **parent_kwargs):
+        # THIS MUST BE THE FIRST POST GENERATION METHOD OR THE OBJECT WILL BE UNSAVED
+        if create:
+            if extracted_parent and parent_kwargs:
+                raise ValueError('Cant pass a parent instance and attributes')
+
+            if not extracted_parent:
+                parent = ApplyHomePageFactory(**parent_kwargs)
+            else:
+                # Assume root node if no parent passed
+                parent = extracted_parent
+
+            parent.add_child(instance=self)
+
     @factory.post_generation
     def forms(self, create, extracted, **kwargs):
         if create:
@@ -98,7 +115,7 @@ class AbstractRelatedFormFactory(factory.DjangoModelFactory):
 class ApplicationBaseFormFactory(AbstractRelatedFormFactory):
     class Meta:
         model = ApplicationBaseForm
-    application = factory.SubFactory(FundTypeFactory, parent=None)
+    application = factory.SubFactory(FundTypeFactory)
 
 
 class ApplicationFormFactory(factory.DjangoModelFactory):
@@ -120,7 +137,7 @@ class RoundFactory(wagtail_factories.PageFactory):
         )
 
     title = factory.Sequence('Round {}'.format)
-    start_date = factory.Sequence(lambda n: datetime.date.today() + datetime.timedelta(days=7 * n))
+    start_date = factory.Sequence(lambda n: datetime.date.today() + datetime.timedelta(days=7 * n + 1))
     end_date = factory.Sequence(lambda n: datetime.date.today() + datetime.timedelta(days=7 * (n + 1)))
     lead = factory.SubFactory(StaffFactory)
 
@@ -149,7 +166,7 @@ class TodayRoundFactory(RoundFactory):
 class RoundBaseFormFactory(AbstractRelatedFormFactory):
     class Meta:
         model = RoundBaseForm
-    round = factory.SubFactory(RoundFactory, parent=None)
+    round = factory.SubFactory(RoundFactory)
 
 
 class LabFactory(wagtail_factories.PageFactory):
@@ -179,7 +196,7 @@ class LabFactory(wagtail_factories.PageFactory):
 class LabBaseFormFactory(AbstractRelatedFormFactory):
     class Meta:
         model = LabBaseForm
-    lab = factory.SubFactory(LabFactory, parent=None)
+    lab = factory.SubFactory(LabFactory)
 
 
 class ApplicationFormDataFactory(FormDataFactory):
@@ -235,6 +252,11 @@ class SealedSubmissionFactory(ApplicationSubmissionFactory):
     )
 
 
+class LabSubmissionFactory(ApplicationSubmissionFactory):
+    round = None
+    page = factory.SubFactory(LabFactory)
+
+
 class ApplicationRevisionFactory(factory.DjangoModelFactory):
     class Meta:
         model = ApplicationRevision
diff --git a/opentech/apply/funds/tests/test_models.py b/opentech/apply/funds/tests/test_models.py
index 4570f9a12ded04f3def74fa8c46884fe8ad440d4..44b07e3891733bd7d965a3a58d94d785edb59433 100644
--- a/opentech/apply/funds/tests/test_models.py
+++ b/opentech/apply/funds/tests/test_models.py
@@ -179,6 +179,7 @@ class TestRoundModelWorkflowAndForms(TestCase):
             self.assertNotEqual(round_form, fund_form)
 
 
+@override_settings(ROOT_URLCONF='opentech.apply.urls')
 class TestFormSubmission(TestCase):
     def setUp(self):
         self.site = Site.objects.first()
diff --git a/opentech/apply/funds/tests/test_views.py b/opentech/apply/funds/tests/test_views.py
index 5e31117a1b44c6bf70e03c547c4489d61f703fdb..ebacea7f3a05e1f73ab122cf40782c50fc7ca73d 100644
--- a/opentech/apply/funds/tests/test_views.py
+++ b/opentech/apply/funds/tests/test_views.py
@@ -4,6 +4,7 @@ from opentech.apply.activity.models import Activity
 from opentech.apply.funds.tests.factories import (
     ApplicationSubmissionFactory,
     ApplicationRevisionFactory,
+    LabSubmissionFactory,
     SealedRoundFactory,
     SealedSubmissionFactory,
 )
@@ -29,6 +30,11 @@ class TestStaffSubmissionView(BaseSubmissionViewTestCase):
         response = self.get_page(submission)
         self.assertContains(response, submission.title)
 
+    def test_can_view_a_lab_submission(self):
+        submission = LabSubmissionFactory()
+        response = self.get_page(submission)
+        self.assertContains(response, submission.title)
+
     def test_can_progress_phase(self):
         submission = ApplicationSubmissionFactory()
         next_status = list(submission.get_actions_for_user(self.user))[0][0]
diff --git a/opentech/apply/funds/views.py b/opentech/apply/funds/views.py
index 40f0870ec2e63e098cf50bccee193ee69322aba7..6d842387e7ecf3c03cdf546ac40f23582062831c 100644
--- a/opentech/apply/funds/views.py
+++ b/opentech/apply/funds/views.py
@@ -208,7 +208,11 @@ class SubmissionSealedView(DetailView):
 
     @classmethod
     def round_is_sealed(cls, submission):
-        return submission.round.specific.is_sealed
+        try:
+            return submission.round.specific.is_sealed
+        except AttributeError:
+            # Its a lab - cant be sealed
+            return False
 
     @classmethod
     def has_peeked(cls, request, submission):
diff --git a/opentech/apply/home/factories.py b/opentech/apply/home/factories.py
new file mode 100644
index 0000000000000000000000000000000000000000..aa53b814af17d25b41e4a9a896fa12f3892c0df5
--- /dev/null
+++ b/opentech/apply/home/factories.py
@@ -0,0 +1,14 @@
+import factory
+import wagtail_factories
+
+from .models import ApplyHomePage
+
+
+class ApplyHomePageFactory(wagtail_factories.PageFactory):
+    class Meta:
+        model = ApplyHomePage
+
+    @factory.post_generation
+    def site(self, create, extracted_site, **site_kwargs):
+        if create:
+            wagtail_factories.SiteFactory(root_page=self, is_default_site=True)
diff --git a/opentech/apply/middleware.py b/opentech/apply/middleware.py
new file mode 100644
index 0000000000000000000000000000000000000000..80daac1236b8eef0b846128f0aa4689609070c63
--- /dev/null
+++ b/opentech/apply/middleware.py
@@ -0,0 +1,17 @@
+from .home.models import ApplyHomePage
+
+
+def apply_url_conf_middleware(get_response):
+    # If we are on a page which belongs to the same site as an ApplyHomePage
+    # we change the url conf to one that includes links to all the logged
+    # in functionality. Login and Logout are included with the global package
+    # of urls
+    def middleware(request):
+        homepage = request.site.root_page.specific
+        if isinstance(homepage, ApplyHomePage):
+            request.urlconf = 'opentech.apply.urls'
+
+        response = get_response(request)
+        return response
+
+    return middleware
diff --git a/opentech/apply/urls.py b/opentech/apply/urls.py
index e730c8025c66f734737c7d20369e1cdfbd58fff1..27483633b8fb3bad18a4649f396e9a4a7758cc62 100644
--- a/opentech/apply/urls.py
+++ b/opentech/apply/urls.py
@@ -3,11 +3,15 @@ from django.urls import include, path
 from .users import urls as users_urls
 from .dashboard import urls as dashboard_urls
 
+from opentech.urls import urlpatterns as base_urlpatterns
+
 
 urlpatterns = [
     path('apply/', include('opentech.apply.funds.urls', 'apply')),
     path('activity/', include('opentech.apply.activity.urls', 'activity')),
-    path('account/', include(users_urls)),
+    path('', include(users_urls)),
     path('dashboard/', include(dashboard_urls)),
     path('hijack/', include('hijack.urls', 'hijack')),
 ]
+
+urlpatterns += base_urlpatterns
diff --git a/opentech/apply/users/forms.py b/opentech/apply/users/forms.py
index b27eab0b8f4091fe4368787ac298499078a473fd..8338010a6bce407dfa03be69e97d03b05f28972e 100644
--- a/opentech/apply/users/forms.py
+++ b/opentech/apply/users/forms.py
@@ -1,5 +1,6 @@
 from django import forms
 from django.contrib.auth import get_user_model
+from django.utils.translation import gettext_lazy as _
 
 from wagtail.users.forms import UserEditForm, UserCreationForm
 
@@ -36,7 +37,10 @@ class ProfileForm(forms.ModelForm):
 
         if not self.instance.has_usable_password():
             # User is registered with oauth - no password change allowed
-            del self.fields['email']
+            email_field = self.fields['email']
+            email_field.disabled = True
+            email_field.required = False
+            email_field.help_text = _('You are registered using OAuth, please contact an admin if you need to change your email address.')
 
     def clean_slack(self):
         slack = self.cleaned_data['slack']
diff --git a/opentech/apply/users/groups.py b/opentech/apply/users/groups.py
index e3b215e3d4f12c57380e9a7cc8e01590b652db70..42a49daa26f41ef5674bb083df6a342098fb35d2 100644
--- a/opentech/apply/users/groups.py
+++ b/opentech/apply/users/groups.py
@@ -2,48 +2,12 @@ STAFF_GROUP_NAME = 'Staff'
 REVIEWER_GROUP_NAME = 'Reviewer'
 
 GROUPS = [
-    {
-        'name': 'Applicant',
-        'permissions': [],
-    },
     {
         'name': REVIEWER_GROUP_NAME,
         'permissions': [],
     },
-    {
-        'name': 'Advisor',
-        'permissions': [],
-    },
     {
         'name': STAFF_GROUP_NAME,
         'permissions': [],
     },
-    {
-        'name': 'Manager',
-        'permissions': [
-            'add_image',
-            'change_image',
-            'delete_image',
-            'add_document',
-            'change_document',
-            'delete_document',
-            'access_admin',
-        ],
-    },
-    {
-        'name': 'Administrator',
-        'permissions': [
-            'add_image',
-            'change_image',
-            'delete_image',
-            'add_document',
-            'change_document',
-            'delete_document',
-            'add_user',
-            'change_user',
-            'delete_user',
-            'access_admin',
-            'change_site',
-        ],
-    }
 ]
diff --git a/opentech/apply/users/management/commands/migrate_users.py b/opentech/apply/users/management/commands/migrate_users.py
index 7d8ef0b505ce603d844db65441b76ba9263d3a83..c101c1c9454622970c9a4e96c82011bc9b63ac52 100644
--- a/opentech/apply/users/management/commands/migrate_users.py
+++ b/opentech/apply/users/management/commands/migrate_users.py
@@ -61,9 +61,8 @@ class Command(BaseCommand):
     def get_user_groups(self, user):
         groups = []
         role_map = {
-            'proposer': 'Applicant',
-            'council': 'Advisor',
-            'administrator': 'Administrator',
+            'council': 'Reviewer',
+            'administrator': 'Editors',
             'dev': 'Administrator',
         }
 
diff --git a/opentech/apply/users/templates/users/activation/email.txt b/opentech/apply/users/templates/users/activation/email.txt
index 864c367647c5ebf060236c606c838da44457c194..a32a55ca6e1e1b1a04c9f40eaf239965f4a6c7c7 100644
--- a/opentech/apply/users/templates/users/activation/email.txt
+++ b/opentech/apply/users/templates/users/activation/email.txt
@@ -4,7 +4,7 @@ Dear {{ name|default:username }},
 
 An account on Open Technology Fund has been created. Activate your account by clicking this link or copying and pasting it to your browser:
 
-{% if site %}{{ site.root_url }}{% else %}{{ base_url }}{% endif %}{% url 'users:activate' uidb64=uid token=token %}
+{% if site %}{{ site.root_url }}{% else %}{{ base_url }}{% endif %}{{ activation_path }}
 
 This link can be used once to log in and will lead you to a page where you can set your password.
 
diff --git a/opentech/apply/users/templates/users/activation/email_subject.txt b/opentech/apply/users/templates/users/activation/email_subject.txt
deleted file mode 100644
index 1f1a8daafc3057f4227badf39bc239a6c131b73a..0000000000000000000000000000000000000000
--- a/opentech/apply/users/templates/users/activation/email_subject.txt
+++ /dev/null
@@ -1 +0,0 @@
-Account details for {{ username }} at Open Technology Fund
diff --git a/opentech/apply/users/templates/users/password_reset/complete.html b/opentech/apply/users/templates/users/password_reset/complete.html
index 00740fd926d8ee3539dabbe12f556a5bfd0b9a84..fb4f06aa4280585f99ae7d1d606bc68b4ce26567 100644
--- a/opentech/apply/users/templates/users/password_reset/complete.html
+++ b/opentech/apply/users/templates/users/password_reset/complete.html
@@ -4,6 +4,6 @@
 {% block title %}{% trans "Reset password" %}{% endblock %} {% block content %}
     <h1>{% trans "Password change successful" %}</h1>
     <p>
-        <a href="{% url 'users:login' %}">{% trans "Log in" %}</a>
+        <a href="{% url 'users_public:login' %}">{% trans "Log in" %}</a>
     </p>
 {% endblock %}
diff --git a/opentech/apply/users/tests/test_forms.py b/opentech/apply/users/tests/test_forms.py
index 06e81fb933f048101100af1a60e7dff680c4f9e8..edb991775afdc6b395f9660b098181322fe9914e 100644
--- a/opentech/apply/users/tests/test_forms.py
+++ b/opentech/apply/users/tests/test_forms.py
@@ -48,10 +48,9 @@ class TestStaffProfileForm(BaseTestProfileForm):
     def setUp(self):
         self.staff = StaffFactory()
 
-    def test_cant_change_password(self):
+    def test_cant_change_email(self):
         new_email = 'me@this.com'
-        form = self.submit_form(self.staff, email=new_email)
-        self.assertFalse('email' in form.fields)
+        self.submit_form(self.staff, email=new_email)
         self.staff.refresh_from_db()
         self.assertNotEqual(new_email, self.staff.email)
 
diff --git a/opentech/apply/users/tests/test_oauth_access.py b/opentech/apply/users/tests/test_oauth_access.py
index 92d3f2ae25fa42123fb5d1530574e3604a1c2d72..1cc2f13ab373fe94f72bb9e3b4d09a753bba97e8 100644
--- a/opentech/apply/users/tests/test_oauth_access.py
+++ b/opentech/apply/users/tests/test_oauth_access.py
@@ -4,6 +4,7 @@ from django.test import TestCase, override_settings
 from django.urls import reverse
 
 
+@override_settings(ROOT_URLCONF='opentech.apply.urls')
 class TestOAuthAccess(TestCase):
     def login(self):
         email = 'test@email.com'
@@ -19,8 +20,12 @@ class TestOAuthAccess(TestCase):
         """
         oauth_page = reverse('users:oauth')
         response = self.client.get(oauth_page, follow=True)
-        self.assertRedirects(response, reverse(
-            'users:login') + '?next=' + reverse('users:oauth'), status_code=301, target_status_code=200)
+        self.assertRedirects(
+            response,
+            reverse('users_public:login') + '?next=' + reverse('users:oauth'),
+            status_code=301,
+            target_status_code=200,
+        )
 
     @override_settings()
     def test_oauth_not_set_up(self):
diff --git a/opentech/apply/users/tests/test_utils.py b/opentech/apply/users/tests/test_utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..8d9c9fa6c4a1dd7a2c167b5bb91ec35f95719045
--- /dev/null
+++ b/opentech/apply/users/tests/test_utils.py
@@ -0,0 +1,12 @@
+from django.core import mail
+from django.test import TestCase
+
+from opentech.apply.users.tests.factories import UserFactory
+
+from ..utils import send_activation_email
+
+
+class TestActivationEmail(TestCase):
+    def test_activation_email_includes_link(self):
+        send_activation_email(UserFactory())
+        self.assertEqual(len(mail.outbox), 1)
diff --git a/opentech/apply/users/tests/test_views.py b/opentech/apply/users/tests/test_views.py
index 1943e508315cfd891b11d2095dd1b5e2639c4af0..e5c2a6dc4320916fe508dae4980bcf12789e1263 100644
--- a/opentech/apply/users/tests/test_views.py
+++ b/opentech/apply/users/tests/test_views.py
@@ -1,9 +1,10 @@
-from django.test import TestCase
+from django.test import override_settings, TestCase
 from django.urls import reverse
 
 from .factories import OAuthUserFactory, StaffFactory, UserFactory
 
 
+@override_settings(ROOT_URLCONF='opentech.apply.urls')
 class BaseTestProfielView(TestCase):
     @classmethod
     def setUpTestData(cls):
@@ -19,7 +20,7 @@ class TestProfileView(BaseTestProfielView):
         self.client.logout()
         response = self.client.get(self.url, follow=True)
         # Initial redirect will be via to https through a 301
-        self.assertRedirects(response, reverse('users:login') + '?next=' + self.url, status_code=301)
+        self.assertRedirects(response, reverse('users_public:login') + '?next=' + self.url, status_code=301)
 
     def test_includes_change_password(self):
         response = self.client.get(self.url, follow=True)
@@ -43,7 +44,3 @@ class TestStaffProfileView(BaseTestProfielView):
     def test_can_set_slack_name(self):
         response = self.client.get(self.url, follow=True)
         self.assertContains(response, 'Slack name')
-
-    def test_can_not_set_email(self):
-        response = self.client.get(self.url, follow=True)
-        self.assertNotContains(response, 'Email')
diff --git a/opentech/apply/users/urls.py b/opentech/apply/users/urls.py
index ddb5fb2634500e85f9f4382dba4354aabbaf32ef..02e7899ca76bf89522a1b0f4d7c153033b404fcf 100644
--- a/opentech/apply/users/urls.py
+++ b/opentech/apply/users/urls.py
@@ -1,4 +1,4 @@
-from django.urls import path
+from django.urls import path, include
 from django.contrib.auth import views as auth_views
 from django.urls import reverse_lazy
 
@@ -7,9 +7,8 @@ from opentech.apply.users.views import AccountView, become, oauth, ActivationVie
 
 app_name = 'users'
 
-urlpatterns = [
-    path('', AccountView.as_view(), name='account'),
-    path('become/', become, name='become'),
+
+public_urlpatterns = [
     path(
         'login/',
         auth_views.LoginView.as_view(
@@ -21,52 +20,58 @@ urlpatterns = [
 
     # Log out
     path('logout/', auth_views.LogoutView.as_view(next_page='/'), name='logout'),
+]
 
-    # Password change
-    path(
-        'password/',
-        auth_views.PasswordChangeView.as_view(
-            template_name="users/change_password.html",
-            success_url=reverse_lazy('users:account')
-        ),
-        name='password_change',
-    ),
 
-    # Password reset
-    path(
-        'reset/',
-        auth_views.PasswordResetView.as_view(
-            template_name='users/password_reset/form.html',
-            email_template_name='users/password_reset/email.txt',
-            success_url=reverse_lazy('users:password_reset_done')
-        ),
-        name='password_reset',
-    ),
-    path(
-        'reset/done/',
-        auth_views.PasswordResetDoneView.as_view(template_name='users/password_reset/done.html'),
-        name='password_reset_done'
-    ),
-    path(
-        'reset/confirm/<uidb64>/<token>/',
-        auth_views.PasswordResetConfirmView.as_view(
-            template_name='users/password_reset/confirm.html',
-            post_reset_login=True,
-            post_reset_login_backend='django.contrib.auth.backends.ModelBackend',
-            success_url=reverse_lazy('users:account')
+urlpatterns = [
+    path('account/', include([
+        path('', AccountView.as_view(), name='account'),
+        path('become/', become, name='become'),
+        path('password/', include([
+            path(
+                'change/',
+                auth_views.PasswordChangeView.as_view(
+                    template_name="users/change_password.html",
+                    success_url=reverse_lazy('users:account')
+                ),
+                name='password_change',
+            ),
+            path(
+                'reset/',
+                auth_views.PasswordResetView.as_view(
+                    template_name='users/password_reset/form.html',
+                    email_template_name='users/password_reset/email.txt',
+                    success_url=reverse_lazy('users:password_reset_done')
+                ),
+                name='password_reset',
+            ),
+            path(
+                'reset/done/',
+                auth_views.PasswordResetDoneView.as_view(template_name='users/password_reset/done.html'),
+                name='password_reset_done'
+            ),
+            path(
+                'reset/confirm/<uidb64>/<token>/',
+                auth_views.PasswordResetConfirmView.as_view(
+                    template_name='users/password_reset/confirm.html',
+                    post_reset_login=True,
+                    post_reset_login_backend='django.contrib.auth.backends.ModelBackend',
+                    success_url=reverse_lazy('users:account')
+                ),
+                name='password_reset_confirm'
+            ),
+            path(
+                'reset/complete/',
+                auth_views.PasswordResetCompleteView.as_view(template_name='users/password_reset/complete.html'),
+                name='password_reset_complete'
+            ),
+        ])),
+        path(
+            'activate/<uidb64>/<token>/',
+            ActivationView.as_view(),
+            name='activate'
         ),
-        name='password_reset_confirm'
-    ),
-    path(
-        'reset/complete/',
-        auth_views.PasswordResetCompleteView.as_view(template_name='users/password_reset/complete.html'),
-        name='password_reset_complete'
-    ),
-    path(
-        'activate/<uidb64>/<token>/',
-        ActivationView.as_view(),
-        name='activate'
-    ),
-    path('activate/password/', create_password, name="activate_password"),
-    path('oauth', oauth, name='oauth'),
+        path('activate/', create_password, name="activate_password"),
+        path('oauth', oauth, name='oauth'),
+    ]))
 ]
diff --git a/opentech/apply/users/utils.py b/opentech/apply/users/utils.py
index 4c40cb43deba360d4a6706f08390a3635a4c78ff..7539e137f579da23f11c50150e0c0dc1fdf9676a 100644
--- a/opentech/apply/users/utils.py
+++ b/opentech/apply/users/utils.py
@@ -3,6 +3,7 @@ from django.contrib.auth.tokens import PasswordResetTokenGenerator
 from django.template.loader import render_to_string
 from django.utils.encoding import force_bytes
 from django.utils.http import urlsafe_base64_encode
+from django.urls import reverse
 
 
 def can_use_oauth_check(user):
@@ -20,23 +21,29 @@ def can_use_oauth_check(user):
     return False
 
 
-def send_activation_email(user, site):
+def send_activation_email(user, site=None):
     """
     Send the activation email. The activation key is the username,
     signed using TimestampSigner.
     """
     token_generator = PasswordResetTokenGenerator()
+    token = token_generator.make_token(user)
+
+    uid = urlsafe_base64_encode(force_bytes(user.pk)).decode()
+
+    activation_path = reverse('users:activate', kwargs={'uidb64': uid, 'token': token})
+
     context = {
         'user': user,
         'name': user.get_full_name(),
         'username': user.get_username(),
-        'uid': urlsafe_base64_encode(force_bytes(user.pk)),
-        'token': token_generator.make_token(user),
+        'activation_path': activation_path,
     }
+
     if site:
         context.update(site=site)
 
-    subject = render_to_string('users/activation/email_subject.txt', context)
+    subject = 'Account details for {username} at Open Technology Fund'.format(**context)
     # Force subject to a single line to avoid header-injection issues.
     subject = ''.join(subject.splitlines())
     message = render_to_string('users/activation/email.txt', context)
diff --git a/opentech/apply/users/views.py b/opentech/apply/users/views.py
index 8f8e3dab59ca43446f461283062957c5c640f132..7dadd850d5bac0ad6c823836d608641d699e36a5 100644
--- a/opentech/apply/users/views.py
+++ b/opentech/apply/users/views.py
@@ -49,7 +49,7 @@ class AccountView(UpdateView):
         )
 
 
-@login_required(login_url=reverse_lazy('users:login'))
+@login_required()
 def become(request):
     if request.POST:
         id = request.POST['user']
@@ -57,7 +57,7 @@ def become(request):
     return redirect('users:account')
 
 
-@login_required(login_url=reverse_lazy('users:login'))
+@login_required()
 @require_oauth_whitelist
 def oauth(request):
     """Generic, empty view for the OAuth associations."""
diff --git a/opentech/apply/utils/testing/tests.py b/opentech/apply/utils/testing/tests.py
index 624a0e774709a6132effa56141744a85f062d82c..c0b0edd1cfd75239c459eedb1d0ae8c0911950d6 100644
--- a/opentech/apply/utils/testing/tests.py
+++ b/opentech/apply/utils/testing/tests.py
@@ -1,6 +1,6 @@
 from django.contrib.messages.storage.fallback import FallbackStorage
 from django.contrib.auth.models import AnonymousUser
-from django.test import TestCase, RequestFactory
+from django.test import override_settings, TestCase, RequestFactory
 from django.urls import reverse
 
 
@@ -17,6 +17,7 @@ def make_request(user=AnonymousUser(), data={}, method='get', site=None):
     return request
 
 
+@override_settings(ROOT_URLCONF='opentech.apply.urls')
 class BaseViewTestCase(TestCase):
     url_name = ''  # resolvable url, you should use "path:to:view:{}" and {} with be replaced with base_view_name
     base_view_name = ''
diff --git a/opentech/public/home/templates/home/home_page.html b/opentech/public/home/templates/home/home_page.html
index 1b66674fdb85860b3672e7e00fae02eb029dc349..de9864f1f1d4734b35cacf95829d39181a5b9215 100644
--- a/opentech/public/home/templates/home/home_page.html
+++ b/opentech/public/home/templates/home/home_page.html
@@ -52,10 +52,7 @@
             </section>
 
             <div class="header__button-container">
-                <a href="{% url 'users:login' %}" class="button button--transparent button--contains-icons">
-                    <svg class="icon icon--person"><use xlink:href="#person-icon"></use></svg>
-                    My OTF
-                </a>
+                {% include "utils/includes/login_button.html" %}
                 <div class="button button--google-translate" id="google_translate_element"></div>
             </div>
         </div>
diff --git a/opentech/public/mailchimp/__init__.py b/opentech/public/mailchimp/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/opentech/public/mailchimp/apps.py b/opentech/public/mailchimp/apps.py
new file mode 100644
index 0000000000000000000000000000000000000000..6825eca974a4a4ece3a2fb3acbc7ab9ae8799f9d
--- /dev/null
+++ b/opentech/public/mailchimp/apps.py
@@ -0,0 +1,5 @@
+from django.apps import AppConfig
+
+
+class MailchimpConfig(AppConfig):
+    name = 'mailchimp'
diff --git a/opentech/public/mailchimp/forms.py b/opentech/public/mailchimp/forms.py
new file mode 100644
index 0000000000000000000000000000000000000000..afda5b9e3f0c0d79da9646a23b3f7c7de40ce82f
--- /dev/null
+++ b/opentech/public/mailchimp/forms.py
@@ -0,0 +1,15 @@
+from django import forms
+
+
+class NewsletterForm(forms.Form):
+    email = forms.EmailField(label='Email Address')
+    fname = forms.CharField(label='First Name', required=False)
+    lname = forms.CharField(label='Last Name', required=False)
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        for field in self.fields.values():
+            class_name = 'input--secondary'
+            if field.required:
+                class_name += ' input__secondary--required'
+            field.widget.attrs = {'class': class_name}
diff --git a/opentech/public/mailchimp/migrations/__init__.py b/opentech/public/mailchimp/migrations/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/opentech/public/mailchimp/models.py b/opentech/public/mailchimp/models.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/opentech/public/mailchimp/templates/mailchimp/newsletter_signup.html b/opentech/public/mailchimp/templates/mailchimp/newsletter_signup.html
new file mode 100644
index 0000000000000000000000000000000000000000..4c70ae9abe8f9e980d69af7188e9d800df553056
--- /dev/null
+++ b/opentech/public/mailchimp/templates/mailchimp/newsletter_signup.html
@@ -0,0 +1,16 @@
+<h4>Get the latest internet freedom news</h4>
+<form class="form" action="{% url "newsletter:subscribe" %}" method="post">
+    <div>
+        {% for field in newsletter_form %}
+        <label for="{{ field.id_for_label }}"{% if field.field.required %} required{% endif %}>
+            <span>{{ field.label }}</span>
+            {% if field.field.required %}
+                <span class="form__required">*</span>
+            {% endif %}
+            {{ field }}
+        {% endfor %}
+        <div class="form-actions form-wrapper">
+            <input type="submit" value="Sign up" class="form-submit link link--button-transparent link--footer-signup">
+        </div>
+    </div>
+</form>
diff --git a/opentech/public/mailchimp/tests.py b/opentech/public/mailchimp/tests.py
new file mode 100644
index 0000000000000000000000000000000000000000..4e838712116aa9e1e3ef5ebae892e6706f7b1d64
--- /dev/null
+++ b/opentech/public/mailchimp/tests.py
@@ -0,0 +1,69 @@
+from unittest import mock
+import re
+
+from django.test import override_settings, TestCase
+from django.urls import reverse
+
+import responses
+
+
+any_url = re.compile(".")
+
+
+class TestNewsletterView(TestCase):
+    url = reverse('newsletter:subscribe')
+
+    def setUp(self):
+        self.origin = 'https://testserver/'
+        self.client.defaults = {'HTTP_ORIGIN': self.origin}
+
+    def test_redirected_home_if_get(self):
+        response = self.client.get(self.url, secure=True, follow=True)
+        request = response.request
+        self.assertRedirects(response, '{}://{}/'.format(request['wsgi.url_scheme'], request['SERVER_NAME']))
+
+    @override_settings(
+        MAILCHIMP_API_KEY='a' * 32,
+        MAILCHIMP_LIST_ID='12345'
+    )
+    @responses.activate
+    def test_can_subscribe(self):
+        responses.add(responses.POST, any_url, json={'id': '1234'}, status=200)
+
+        response = self.client.post(self.url, data={'email': 'email@email.com'}, secure=True, follow=True)
+        self.assertRedirects(response, self.origin)
+
+        messages = list(response.context['messages'])
+        self.assertEqual(len(messages), 1)
+        self.assertIn('Thank you', str(messages[0]))
+
+    def test_error_in_form(self):
+        response = self.client.post(self.url, data={'email': 'email_is_bad.com'}, secure=True, follow=True)
+        self.assertRedirects(response, self.origin)
+
+        messages = list(response.context['messages'])
+        self.assertEqual(len(messages), 1)
+        self.assertIn('errors with', str(messages[0]))
+
+    @override_settings(
+        MAILCHIMP_API_KEY='a' * 32,
+        MAILCHIMP_LIST_ID='12345'
+    )
+    @responses.activate
+    @mock.patch('opentech.public.mailchimp.views.logging')
+    def test_error_with_mailchimp(self, logging):
+        # Copied from the mailchimp playground
+        response_data = {
+            "title": "Invalid Resource",
+            "status": 400,
+            "detail": "Please provide a valid email address.",
+        }
+        responses.add(responses.POST, any_url, json=response_data, status=400)
+        response = self.client.post(self.url, data={'email': 'email@email.com'}, secure=True, follow=True)
+
+        self.assertRedirects(response, self.origin)
+
+        messages = list(response.context['messages'])
+        self.assertEqual(len(messages), 1)
+        self.assertIn('problem', str(messages[0]))
+        logging.info.assert_called_once_with(response_data)
diff --git a/opentech/public/mailchimp/urls.py b/opentech/public/mailchimp/urls.py
new file mode 100644
index 0000000000000000000000000000000000000000..4fe8fd700905dce757a61635859439915c5eb90f
--- /dev/null
+++ b/opentech/public/mailchimp/urls.py
@@ -0,0 +1,11 @@
+from django.urls import path
+
+from .views import MailchimpSubscribeView
+
+
+app_name = 'newsletter'
+
+
+urlpatterns = [
+    path('subscribe/', MailchimpSubscribeView.as_view(), name='subscribe')
+]
diff --git a/opentech/public/mailchimp/views.py b/opentech/public/mailchimp/views.py
new file mode 100644
index 0000000000000000000000000000000000000000..19a7f6795851dc2bbf029d4035a9e7772b9ee436
--- /dev/null
+++ b/opentech/public/mailchimp/views.py
@@ -0,0 +1,84 @@
+import logging
+
+from django.conf import settings
+from django.contrib import messages
+from django.http import HttpResponseRedirect
+from django.utils.decorators import method_decorator
+from django.utils.translation import ugettext_lazy as _
+from django.views.decorators.csrf import csrf_exempt
+from django.views.generic import RedirectView
+from django.views.generic.edit import FormMixin
+
+from mailchimp3 import MailChimp
+
+from .forms import NewsletterForm
+
+logging.getLogger('opentech')
+
+
+@method_decorator(csrf_exempt, name='dispatch')
+class MailchimpSubscribeView(FormMixin, RedirectView):
+    form_class = NewsletterForm
+
+    def post(self, request, *args, **kwargs):
+        form = self.get_form()
+        if form.is_valid():
+            return self.form_valid(form)
+        else:
+            return self.form_invalid(form)
+
+    def form_invalid(self, form):
+        self.error(form)
+        return HttpResponseRedirect(self.get_success_url())
+
+    def form_valid(self, form):
+        mailchimp_enabled = settings.MAILCHIMP_API_KEY and settings.MAILCHIMP_LIST_ID
+
+        dummy_key = 'a' * 32
+
+        client = MailChimp(mc_api=settings.MAILCHIMP_API_KEY or dummy_key, timeout=5.0, enabled=mailchimp_enabled)
+
+        data = form.cleaned_data.copy()
+        email = data.pop('email')
+        data = {
+            k.upper(): v
+            for k, v in data.items()
+        }
+        try:
+            client.lists.members.create(settings.MAILCHIMP_LIST_ID, {
+                'email_address': email,
+                'status': 'pending',
+                'merge_fields': data,
+            })
+        except Exception as e:
+            self.warning(e)
+        else:
+            if mailchimp_enabled:
+                self.success()
+            else:
+                self.warning(Exception(
+                    'Incorrect Mailchimp configuration: API_KEY: {}, LIST_ID: {}'.format(
+                        str(settings.MAILCHIMP_API_KEY),
+                        str(settings.MAILCHIMP_LIST_ID),
+                    )
+                ))
+
+        return super().form_valid(form)
+
+    def error(self, form):
+        messages.error(self.request, _('Sorry, there were errors with your form.') + str(form.errors))
+
+    def warning(self, e):
+        messages.warning(self.request, _('Sorry, there has been an problem. Please try again later.'))
+        logging.info(e.args[0])
+
+    def success(self):
+        messages.success(self.request, _('Thank you for subscribing'))
+
+    def get_success_url(self):
+        # Go back to where you came from
+        return self.request.META['HTTP_ORIGIN']
+
+    def get_redirect_url(self):
+        # We don't know where you came from, go home
+        return '/'
diff --git a/opentech/public/navigation/migrations/0002_remove_unused_navigation_elements.py b/opentech/public/navigation/migrations/0002_remove_unused_navigation_elements.py
index 378abc32a7fe7d45476407628b328a0ff6dcaf0d..e3a9d091357f485095340e4bd6c7d8e6647bfa70 100644
--- a/opentech/public/navigation/migrations/0002_remove_unused_navigation_elements.py
+++ b/opentech/public/navigation/migrations/0002_remove_unused_navigation_elements.py
@@ -1,5 +1,6 @@
 # Generated by Django 2.0.2 on 2018-08-09 11:13
 
+
 from django.db import migrations
 
 
diff --git a/opentech/public/navigation/templates/navigation/footerlinks.html b/opentech/public/navigation/templates/navigation/footerlinks.html
deleted file mode 100644
index 098dd8df5b83a3baa07ec85ca9d69df1e2a7fc7d..0000000000000000000000000000000000000000
--- a/opentech/public/navigation/templates/navigation/footerlinks.html
+++ /dev/null
@@ -1,8 +0,0 @@
-{% load wagtailcore_tags %}
-<nav role="navigation" aria-label="Tertiary">
-    <ul class="nav nav--tertiary">
-        {% for link in footerlinks %}
-            {% include_block link with class="footer" %}
-        {% endfor %}
-    </ul>
-</nav>
diff --git a/opentech/public/navigation/templates/navigation/footernav.html b/opentech/public/navigation/templates/navigation/footernav.html
deleted file mode 100644
index 576feaf688b5dd281bece692256ac135a9c7f8bf..0000000000000000000000000000000000000000
--- a/opentech/public/navigation/templates/navigation/footernav.html
+++ /dev/null
@@ -1,6 +0,0 @@
-{% load wagtailcore_tags %}
-<nav class="grid grid--narrow" role="navigation" aria-label="Tertiary">
-    {% for footer in footernav %}
-        {% include_block footer %}
-    {% endfor %}
-</nav>
diff --git a/opentech/public/navigation/templates/navigation/primarynav.html b/opentech/public/navigation/templates/navigation/primarynav.html
index 4b1ddb5cdb5fe08e408f59e8f7e075e32ddab282..57b587c8af74afbacc7be1782008d5742f5f5639 100644
--- a/opentech/public/navigation/templates/navigation/primarynav.html
+++ b/opentech/public/navigation/templates/navigation/primarynav.html
@@ -6,8 +6,5 @@
         {% endfor %}
     </ul>
 </nav>
-<a href="{% url 'users:login' %}" class="link link--button-transparent link--mobile-standout">
-    <svg class="icon"><use xlink:href="#person-icon"></use></svg>
-    My OTF
-</a>
-<a href="#" class="link link--button-secondary link--mobile-standout">Apply</a>
+{% include "utils/includes/login_button.html" with class="link--mobile-standout" %}
+<a href="{% pageurl APPLY_SITE.root_page %}" class="link link--button-secondary link--mobile-standout">Apply</a>
diff --git a/opentech/public/navigation/templates/navigation/secondarynav.html b/opentech/public/navigation/templates/navigation/secondarynav.html
deleted file mode 100644
index 3341960e6a5be2e1b89e4176b4b9309ec62f7cfb..0000000000000000000000000000000000000000
--- a/opentech/public/navigation/templates/navigation/secondarynav.html
+++ /dev/null
@@ -1,8 +0,0 @@
-{% load wagtailcore_tags %}
-<nav role="navigation" aria-label="Secondary">
-    <ul class="nav nav--secondary" role="menubar">
-        {% for link in secondarynav %}
-            {% include_block link %}
-        {% endfor %}
-    </ul>
-</nav>
diff --git a/opentech/public/navigation/templates/navigation/sidebar.html b/opentech/public/navigation/templates/navigation/sidebar.html
deleted file mode 100644
index b322e2c7f2e50a53f3192c9127bd577aa72d2d8a..0000000000000000000000000000000000000000
--- a/opentech/public/navigation/templates/navigation/sidebar.html
+++ /dev/null
@@ -1,14 +0,0 @@
-{% load wagtailcore_tags %}
-{% if children.exists %}
-    <aside class="sidebar">
-        <div class="sidebar__inner">
-            <h5>In this section</h5>
-            <ul>
-                {% for child in children %}
-                <li><a href="{% pageurl child %}">{{ child.title }}</a></li>
-                {% endfor %}
-            </ul>
-        </div>
-    </aside>
-{% endif %}
-
diff --git a/opentech/public/navigation/templatetags/navigation_tags.py b/opentech/public/navigation/templatetags/navigation_tags.py
index 4a9cf1cd8ba75eec3cd13ead7fd2e4819126fa88..84ac38eddfe2816b4808fd7602d0449130d05d79 100644
--- a/opentech/public/navigation/templatetags/navigation_tags.py
+++ b/opentech/public/navigation/templatetags/navigation_tags.py
@@ -11,7 +11,9 @@ register = template.Library()
 def primarynav(context):
     request = context['request']
     site = context.get('PUBLIC_SITE', request.site)
+    apply_site = context.get('APPLY_SITE', request.site)
     return {
         'primarynav': NavigationSettings.for_site(site).primary_navigation,
         'request': request,
+        'APPLY_SITE': apply_site,
     }
diff --git a/opentech/public/urls.py b/opentech/public/urls.py
index c24a04b4f01bffc29ac886b18f0a3326b6eebb31..40b2bb96aa3f0b5df11dc0c953999759bd8b36d5 100644
--- a/opentech/public/urls.py
+++ b/opentech/public/urls.py
@@ -1,7 +1,10 @@
-from django.urls import path
+from django.urls import include, path
 
 from .search import views as search_views
+from .mailchimp import urls as newsletter_urls
+
 
 urlpatterns = [
     path('search/', search_views.search, name='search'),
+    path('newsletter/', include(newsletter_urls))
 ]
diff --git a/opentech/public/utils/context_processors.py b/opentech/public/utils/context_processors.py
index 2444fdb1b890c218c1189a74039e68a935ecdbd2..149a40181ae1a97390338f32baa92c4c174ed096 100644
--- a/opentech/public/utils/context_processors.py
+++ b/opentech/public/utils/context_processors.py
@@ -1,9 +1,12 @@
 from opentech.apply.home.models import ApplyHomePage
 from opentech.public.home.models import HomePage
 
+from opentech.public.mailchimp.forms import NewsletterForm
+
 
 def global_vars(request):
     return {
         'APPLY_SITE': ApplyHomePage.objects.first().get_site(),
         'PUBLIC_SITE': HomePage.objects.first().get_site(),
+        'newsletter_form': NewsletterForm()
     }
diff --git a/opentech/public/utils/templates/utils/includes/login_button.html b/opentech/public/utils/templates/utils/includes/login_button.html
new file mode 100644
index 0000000000000000000000000000000000000000..21b6e461c7c0d39be25fbfeea8fa21ae22a75ea3
--- /dev/null
+++ b/opentech/public/utils/templates/utils/includes/login_button.html
@@ -0,0 +1,4 @@
+<a href="{{ request.scheme }}://{{ APPLY_SITE }}{% url 'users_public:login' %}" class="button button--transparent button--contains-icons {{ class }}">
+    <svg class="icon icon--person"><use xlink:href="#person-icon"></use></svg>
+    My OTF
+</a>
diff --git a/opentech/settings/base.py b/opentech/settings/base.py
index 3c529f26e9559dfa840a4a8c86db6bd843ea453e..a1c0454510c658577ec5bfacebaccbeb9e5d3b53 100644
--- a/opentech/settings/base.py
+++ b/opentech/settings/base.py
@@ -28,6 +28,7 @@ INSTALLED_APPS = [
 
     'opentech.public.funds',
     'opentech.public.home',
+    'opentech.public.mailchimp',
     'opentech.public.navigation',
     'opentech.public.news',
     'opentech.public.people',
@@ -93,6 +94,8 @@ MIDDLEWARE = [
 
     'wagtail.core.middleware.SiteMiddleware',
     'wagtail.contrib.redirects.middleware.RedirectMiddleware',
+
+    'opentech.apply.middleware.apply_url_conf_middleware',
 ]
 
 ROOT_URLCONF = 'opentech.urls'
@@ -216,7 +219,7 @@ WAGTAIL_USER_EDIT_FORM = 'opentech.apply.users.forms.CustomUserEditForm'
 WAGTAIL_USER_CREATION_FORM = 'opentech.apply.users.forms.CustomUserCreationForm'
 WAGTAIL_USER_CUSTOM_FIELDS = ['full_name']
 
-LOGIN_URL = 'users:login'
+LOGIN_URL = 'users_public:login'
 LOGIN_REDIRECT_URL = 'dashboard:dashboard'
 
 AUTHENTICATION_BACKENDS = (
@@ -224,6 +227,7 @@ AUTHENTICATION_BACKENDS = (
     'django.contrib.auth.backends.ModelBackend',
 )
 
+
 # Logging
 
 LOGGING = {
@@ -315,7 +319,7 @@ SOCIAL_AUTH_GOOGLE_OAUTH2_WHITELISTED_DOMAINS = STAFF_EMAIL_DOMAINS
 SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = ''
 SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = ''
 
-SOCIAL_AUTH_LOGIN_ERROR_URL = 'users:login'
+SOCIAL_AUTH_LOGIN_ERROR_URL = 'users_public:login'
 SOCIAL_AUTH_NEW_ASSOCIATION_REDIRECT_URL = 'users:account'
 
 # For pipelines, see http://python-social-auth.readthedocs.io/en/latest/pipeline.html?highlight=pipelines#authentication-pipeline
@@ -369,3 +373,7 @@ if 'REDIS_URL' in env:
     CELERY_BROKER_URL = env.get('REDIS_URL')
 else:
     CELERY_TASK_ALWAYS_EAGER = True
+
+
+MAILCHIMP_API_KEY = env.get('MAILCHIMP_API_KEY')
+MAILCHIMP_LIST_ID = env.get('MAILCHIMP_LIST_ID')
diff --git a/opentech/static_src/src/sass/public/components/_form.scss b/opentech/static_src/src/sass/public/components/_form.scss
index 1d816674003ee53ff23e93da1afc5777c4b4d9d9..d8d2e59d39c59787e54339a453f01abfa86a1a89 100644
--- a/opentech/static_src/src/sass/public/components/_form.scss
+++ b/opentech/static_src/src/sass/public/components/_form.scss
@@ -155,7 +155,7 @@
     input[type='text']:not(.input--secondary),
     input[type='date'],
     input[type='time'],
-    input[type='email'],
+    input[type='email']:not(.input--secondary),
     input[type='number'],
     input[type='password'],
     input[type='datetime-local'] {
diff --git a/opentech/static_src/src/sass/public/components/_messages.scss b/opentech/static_src/src/sass/public/components/_messages.scss
new file mode 100644
index 0000000000000000000000000000000000000000..a732b3c02c88324a2409d84b2ed4c7136d6bd1db
--- /dev/null
+++ b/opentech/static_src/src/sass/public/components/_messages.scss
@@ -0,0 +1,44 @@
+.messages {
+    position: relative;
+    right: 50%;
+    left: 50%;
+    width: 100vw;
+    margin-right: -50vw;
+    margin-left: -50vw;
+
+    &__text {
+        position: relative;
+        max-height: 1000px;
+        padding: 15px;
+        padding-right: 35px;
+        border: solid 1px;
+
+        &--info , &--success {
+            background: $color--mint;
+            border-color: darken($color--mint, 20%);
+        }
+
+        &--warning, &--error {
+            font-weight: bold;
+            color: $color--white;
+            background: $color--error;
+            border-color: darken($color--error, 20%);
+        }
+
+        &--hide {
+            max-height: 0;
+            padding-top: 0;
+            padding-bottom: 0;
+            border: 0 none;
+            transition: all $transition; // sass-lint:disable-line no-transition-all
+            transform-origin: top;
+        }
+    }
+
+    &__close {
+        position: absolute;
+        top: 15px;
+        right: 15px;
+
+    }
+}
diff --git a/opentech/static_src/src/sass/public/layout/_footer.scss b/opentech/static_src/src/sass/public/layout/_footer.scss
index a1f5d97e3d93670304c1c4c8bd4994d426d81eac..ac71e029cd5a8da5db2e8bf03f0fd2fd95203b55 100644
--- a/opentech/static_src/src/sass/public/layout/_footer.scss
+++ b/opentech/static_src/src/sass/public/layout/_footer.scss
@@ -45,16 +45,18 @@
         }
     }
 
-    input[type='text'] {
-        width: 100%;
-        max-width: 390px;
-        margin-bottom: 1rem;
-        color: $color--white;
-        background: transparent;
-        border-top: 0;
-        border-right: 0;
-        border-bottom: 4px solid $color--light-blue;
-        border-left: 0;
+    input{
+        &[type='text'], &[type='email'] {
+            width: 100%;
+            max-width: 390px;
+            margin-bottom: 1rem;
+            color: $color--white;
+            background: transparent;
+            border-top: 0;
+            border-right: 0;
+            border-bottom: 4px solid $color--light-blue;
+            border-left: 0;
+        }
     }
 
     label {
diff --git a/opentech/static_src/src/sass/public/main.scss b/opentech/static_src/src/sass/public/main.scss
index de867a4a611b89cc7c5a13b4bdca4800c758e580..8928471a2984f625853c0b1af4699162ca4ef311 100755
--- a/opentech/static_src/src/sass/public/main.scss
+++ b/opentech/static_src/src/sass/public/main.scss
@@ -28,6 +28,7 @@
 @import 'components/list';
 @import 'components/listing';
 @import 'components/media-box';
+@import 'components/messages';
 @import 'components/nav';
 @import 'components/responsive-object';
 @import 'components/rich-text';
@@ -40,4 +41,3 @@
 @import 'layout/sidebar';
 
 // Pages
-
diff --git a/opentech/templates/base-apply.html b/opentech/templates/base-apply.html
index 1d2903dd3c9f6a98fe151682ed8308e221339c40..5ebdb2b767151d11ca7f935601ab5c8f63b3095c 100644
--- a/opentech/templates/base-apply.html
+++ b/opentech/templates/base-apply.html
@@ -73,7 +73,7 @@
                         <svg class="icon"><use xlink:href="#person-icon"></use></svg>
                         {{ request.user }}
                     </a>
-                    <a href="{% url 'users:logout' %}" class="link link--button-transparent link--mobile-standout">Logout</a>
+                    <a href="{% url 'users_public:logout' %}" class="link link--button-transparent link--mobile-standout">Logout</a>
                 </section>
 
                 <div class="header__button-container">
@@ -81,7 +81,7 @@
                         <svg class="icon icon--person"><use xlink:href="#person-icon"></use></svg>
                         {{ request.user }}
                     </a>
-                    <a href="{% url 'users:logout' %}" class="button button--transparent button--narrow">
+                    <a href="{% url 'users_public:logout' %}" class="button button--transparent button--narrow">
                         Log Out
                     </a>
                 </div>
diff --git a/opentech/templates/base.html b/opentech/templates/base.html
index 722aadef3d9d76b5a268d64bfcc17d4ed74c5a4f..0730652a903cbaaa9820a9c56e44515b8dab15bb 100644
--- a/opentech/templates/base.html
+++ b/opentech/templates/base.html
@@ -118,10 +118,7 @@
                     </section>
 
                     <div class="header__button-container">
-                        <a href="{% url 'users:login' %}" class="button button--transparent button--contains-icons">
-                            <svg class="icon icon--person"><use xlink:href="#person-icon"></use></svg>
-                            My OTF
-                        </a>
+                        {% include "utils/includes/login_button.html" %}
                         <div class="button button--google-translate" id="google_translate_element"></div>
                     </div>
                 </div>
@@ -153,34 +150,7 @@
         <footer class="footer">
             <div class="grid grid--two wrapper wrapper--large">
                 <div class="footer__inner">
-                    <h4>Get the latest internet freedom news</h4>
-                    <form class="form">
-                        <div>
-                            <div class="mailchimp-signup-subscribe-form-description"></div>
-                            <div id="mailchimp-newsletter-32632431e3-mergefields" class="mailchimp-newsletter-mergefields">
-                                <div class="form-item form-type-textfield form-item-mergevars-EMAIL">
-                                    <label for="edit-mergevars-email">Email Address <span class="form-required" title="This field is required.">*</span></label>
-                                    <input type="text" id="edit-mergevars-email" name="mergevars[EMAIL]" value="" size="25" maxlength="128" class="form-text required input--secondary">
-                                </div>
-
-                                <div class="form-item form-type-textfield form-item-mergevars-FNAME">
-                                    <label for="edit-mergevars-fname">First Name </label>
-                                    <input type="text" id="edit-mergevars-fname" name="mergevars[FNAME]" value="" size="25" maxlength="128" class="form-text input--secondary">
-                                </div>
-
-                                <div class="form-item form-type-textfield form-item-mergevars-LNAME">
-                                    <label for="edit-mergevars-lname">Last Name </label>
-                                    <input type="text" id="edit-mergevars-lname" name="mergevars[LNAME]" value="" size="25" maxlength="128" class="form-text input--secondary">
-                                </div>
-
-                            </div>
-                            <input type="hidden" name="form_build_id" value="form-2Dy9x5istHLUmufjcHabtyuZ_niL-RlfSoHBIq39hpI">
-                            <input type="hidden" name="form_id" value="mailchimp_signup_subscribe_block_otf_newsletter_form">
-                            <div class="form-actions form-wrapper" id="edit-actions--3">
-                                <input type="submit" id="edit-submit--3" name="op" value="Sign up" class="form-submit link link--button-transparent link--footer-signup">
-                            </div>
-                        </div>
-                    </form>
+                    {% include "mailchimp/newsletter_signup.html" %}
                 </div>
 
                 <div class="footer__inner">
@@ -199,12 +169,10 @@
                         <p>
                             <a href="mailto:hello@opentech.fund">hello@opentech.fund</a></br>
                             <a href="mailto:press@opentech.fund">press@opentech.fund</a></br>
-                            <span>PGP: 67AC DDCF B909 4685 36DD BC03 F766 3861 965A 90D2</span>
+                            <span>PGP: <a href="https://keybase.io/opentechfund/pgp_keys.asc?fingerprint=67acddcfb909468536ddbc03f7663861965a90d2">67AC DDCF B909 4685 36DD BC03 F766 3861 965A 90D2</a></span>
                         </p>
 
-                        <p><a href="/rss.xml">RSS Feed</a></p>
-
-                        <p><a class="link link--underlined" href="#">Terms of Use</a></p>
+                        <p><a class="link link--underlined" href="/tos">Terms of Use</a></p>
 
                         <p>Test the OTF website for censorship</p>
 
diff --git a/opentech/urls.py b/opentech/urls.py
index ccf767d79944263b3d5809335c7e0312f9530210..6ccf53e45e08630bc26257b714c8b501746210f4 100644
--- a/opentech/urls.py
+++ b/opentech/urls.py
@@ -11,7 +11,7 @@ from wagtail.core import urls as wagtail_urls
 from wagtail.documents import urls as wagtaildocs_urls
 
 from opentech.public import urls as public_urls
-from opentech.apply import urls as apply_urls
+from opentech.apply.users.urls import public_urlpatterns as user_urls
 
 
 urlpatterns = [
@@ -21,7 +21,7 @@ urlpatterns = [
     path('documents/', include(wagtaildocs_urls)),
     path('sitemap.xml', sitemap),
     path('', include(public_urls)),
-    path('', include(apply_urls)),
+    path('', include((user_urls, 'users_public'))),
     path('', include('social_django.urls', namespace='social')),
     path('tinymce/', include('tinymce.urls')),
     path('select2/', include('django_select2.urls')),
diff --git a/requirements.txt b/requirements.txt
index 0ea9b0b33fa436dc7538579fffaa11c5336c4588..4a5561150c9302752af377776340b269fe8ce696 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -18,7 +18,7 @@ celery==4.2.1
 factory_boy==2.9.2
 # wagtail_factories - waiting on merge and release form master branch
 git+git://github.com/mvantellingen/wagtail-factories.git#egg=wagtail_factories
-responses == 0.9.0
+responses==0.9.0
 
 flake8
 
@@ -33,3 +33,4 @@ whitenoise==2.0.4
 uwsgi==2.0.15
 ConcurrentLogHandler==0.9.1
 raven==6.9.0
+mailchimp3==3.0.4