diff --git a/core/views.py b/core/views.py
index 0a22afd1d3424d84a0f586e8b463324a469263ec..9099aa4f3515c4beca51fb4cae2e19e52bc45f01 100644
--- a/core/views.py
+++ b/core/views.py
@@ -1,4 +1,7 @@
 # coding: utf-8
+from django import http
+
+import unicodecsv as csv
 
 
 class PaginationMixin(object):
@@ -22,7 +25,7 @@ class PaginationMixin(object):
     def get_page_range(self, page):
         pages = []
 
-        if page.paginator.num_pages != 1:
+        if page and page.paginator.num_pages != 1:
             for i in page.paginator.page_range:
                 if page.number - 4 < i < page.number + 4:
                     pages.append(i)
@@ -57,3 +60,29 @@ class GridListMixin(object):
         c = super(GridListMixin, self).get_context_data(**kwargs)
         c['grid_list'] = True
         return c
+
+
+class CSVDownloadMixin(object):
+    def get_paginate_by(self, queryset):
+        if self.request.GET.get('csv', None) is None:
+            return super(CSVDownloadMixin, self).get_paginate_by(queryset)
+        return None
+
+    def render_to_csv_response(self, context, **kwargs):
+        response = http.HttpResponse(content_type='text/csv')
+
+        writer = csv.writer(response)
+        for result in self.get_csv_results(context, **kwargs):
+            writer.writerow(self.get_csv_row(result))
+
+        response['Content-Disposition'] = 'attachment; filename="%s.csv"' % (
+            self.csv_name)
+
+        return response
+
+    def render_to_response(self, context, **kwargs):
+        if self.request.GET.get('csv', None) is None:
+            return super(CSVDownloadMixin, self).render_to_response(
+                context, **kwargs)
+
+        return self.render_to_csv_response(context, **kwargs)
diff --git a/memopol/tests/response_fixtures/RepresentativeListTest.test_page1_paginateby12_displaylist/content b/memopol/tests/response_fixtures/RepresentativeListTest.test_page1_paginateby12_displaylist/content
index 52bc54725a36530848ee06588fed49687e199c32..2f7442002579e97b8e971a93e2eaaff5e4420be7 100644
--- a/memopol/tests/response_fixtures/RepresentativeListTest.test_page1_paginateby12_displaylist/content
+++ b/memopol/tests/response_fixtures/RepresentativeListTest.test_page1_paginateby12_displaylist/content
@@ -84,6 +84,10 @@
       <input type='submit' value='Go' />
 
     </form>
+    <a href='?csv'>
+      Download data as CSV
+
+    </a>
   
 
   <div class='pagination-block'>
diff --git a/memopol/tests/response_fixtures/RepresentativeListTest.test_page1_paginateby12_displaylist_searchjoly/content b/memopol/tests/response_fixtures/RepresentativeListTest.test_page1_paginateby12_displaylist_searchjoly/content
index d88608d79697a08612b5737b907f0e0393ce658a..bebce76fbdf9224de743ab35517caaf4478306af 100644
--- a/memopol/tests/response_fixtures/RepresentativeListTest.test_page1_paginateby12_displaylist_searchjoly/content
+++ b/memopol/tests/response_fixtures/RepresentativeListTest.test_page1_paginateby12_displaylist_searchjoly/content
@@ -84,6 +84,10 @@
       <input type='submit' value='Go' />
 
     </form>
+    <a href='?search=joly&csv'>
+      Download data as CSV
+
+    </a>
   
 
   <div class='pagination-block'>
diff --git a/memopol/tests/response_fixtures/RepresentativeListTest.test_page1_paginateby24_displaygrid/content b/memopol/tests/response_fixtures/RepresentativeListTest.test_page1_paginateby24_displaygrid/content
index 5f0203ce0e42de6bb045350124117dbe8873fd9a..79b8aed01fae601b79960277d0e3cae4ec9b254f 100644
--- a/memopol/tests/response_fixtures/RepresentativeListTest.test_page1_paginateby24_displaygrid/content
+++ b/memopol/tests/response_fixtures/RepresentativeListTest.test_page1_paginateby24_displaygrid/content
@@ -84,6 +84,10 @@
       <input type='submit' value='Go' />
 
     </form>
+    <a href='?csv'>
+      Download data as CSV
+
+    </a>
   
 
   <div class='pagination-block'>
diff --git a/memopol/tests/response_fixtures/RepresentativeListTest.test_page2_paginateby12_displaylist/content b/memopol/tests/response_fixtures/RepresentativeListTest.test_page2_paginateby12_displaylist/content
index 9737215355aeee49b56e07996947ad0af055a124..fb66c4b0e35a89cfacf260da0252b77cc4cfbd76 100644
--- a/memopol/tests/response_fixtures/RepresentativeListTest.test_page2_paginateby12_displaylist/content
+++ b/memopol/tests/response_fixtures/RepresentativeListTest.test_page2_paginateby12_displaylist/content
@@ -84,6 +84,10 @@
       <input type='submit' value='Go' />
 
     </form>
+    <a href='?csv'>
+      Download data as CSV
+
+    </a>
   
 
   <div class='pagination-block'>
diff --git a/memopol/tests/response_fixtures/RepresentativeListTest.test_page2_paginateby24_displaylist/content b/memopol/tests/response_fixtures/RepresentativeListTest.test_page2_paginateby24_displaylist/content
index 6ee36005948624931aca70a0e1974ed19b467fd6..5513d5c2c57f27c49e446e1b9676ae3132f2e4ef 100644
--- a/memopol/tests/response_fixtures/RepresentativeListTest.test_page2_paginateby24_displaylist/content
+++ b/memopol/tests/response_fixtures/RepresentativeListTest.test_page2_paginateby24_displaylist/content
@@ -84,6 +84,10 @@
       <input type='submit' value='Go' />
 
     </form>
+    <a href='?csv'>
+      Download data as CSV
+
+    </a>
   
 
   <div class='pagination-block'>
diff --git a/memopol/views.py b/memopol/views.py
index 952ec17b106e44758cbaf5385e0b57447344a424..e668d1d45d615fc626d16e5eb2aa562982a6b3a5 100644
--- a/memopol/views.py
+++ b/memopol/views.py
@@ -1,7 +1,7 @@
 # Project specific "glue" coupling of all apps
 from django.db import models
 
-from core.views import GridListMixin, PaginationMixin
+from core.views import GridListMixin, PaginationMixin, CSVDownloadMixin
 from representatives import views as representatives_views
 from representatives.models import Representative
 from representatives_votes import views as representatives_votes_views
@@ -10,8 +10,28 @@ from representatives_positions.forms import PositionForm
 from representatives_recommendations.models import ScoredVote
 
 
-class RepresentativeList(PaginationMixin, GridListMixin,
-        representatives_views.RepresentativeList):
+class RepresentativeList(
+    CSVDownloadMixin,
+    GridListMixin,
+    PaginationMixin,
+    representatives_views.RepresentativeList
+):
+
+    csv_name = 'meps.csv'
+
+    def get_csv_results(self, context, **kwargs):
+        qs = super(RepresentativeList, self).get_queryset()
+        qs = qs.prefetch_related('email_set')
+        return [self.add_representative_country_and_main_mandate(r)
+                for r in qs]
+
+    def get_csv_row(self, obj):
+        return (
+            obj.full_name,
+            u', '.join([e.email for e in obj.email_set.all()]),
+            obj.main_mandate.group.abbreviation,
+            obj.country,
+        )
 
     queryset = Representative.objects.filter(
         active=True).select_related('score')
diff --git a/setup.py b/setup.py
index 788bcfe6d7b38a9920d8a723ce8e64ba1dc44f77..ba922229938b0c3fbb0364a5eead728b53cbb290 100644
--- a/setup.py
+++ b/setup.py
@@ -24,6 +24,7 @@ setup(name='political-memory',
         'ijson>=2.2,<2.3',
         'lesscpy',
         'python-dateutil>=2.4,<2.5',
+        'unicodecsv==0.14.1',
         'pytz==2015.7',
         'django-suit',
     ],
diff --git a/templates/representatives/representative_list.haml b/templates/representatives/representative_list.haml
index 4288114df4f021a5cda06d86bc5006f8b2585713..525f375cff9bb0f4fe3a49c5b24c305e05ae153f 100644
--- a/templates/representatives/representative_list.haml
+++ b/templates/representatives/representative_list.haml
@@ -14,6 +14,9 @@
       %input{id:"search", type:"text", name:"search"}
       %input{type:"submit", value:"Go"}
 
+    %a{href:"?{% if request.GET.search %}search={{ request.GET.search }}&{% endif %}csv"}
+      - trans 'Download data as CSV'
+
   - include 'core/blocks/pagination.html'
 
   - block list