diff --git a/submissions/services.py b/submissions/services.py
index bd16fb2ae70960507034ca3e46f8b6780a85fe87..4448bea5c2a0d39b01afd1432be65eab797e5898 100644
--- a/submissions/services.py
+++ b/submissions/services.py
@@ -1,67 +1,122 @@
 # Module for making external api calls as needed in the submissions cycle
-import feedparser
+import feedparser, requests, pprint
+from io import BytesIO
 
 from .models import *
+import re
 
 
 class ArxivCaller():
-    def lookup_article(identifier):
-        # Pre-checks
-        if same_version_exists(identifier)
-            return False, "This preprint version has already been submitted to SciPost."
+    """ Performs an Arxiv article lookup for given identifier """
+
+    # State of the caller
+    isvalid = None
+    errorcode = ''
+    resubmission = False
+    arxiv_journal_ref = ''
+    arxiv_doi = ''
+    metadata = {}
+    query_base_url = 'http://export.arxiv.org/api/query?id_list=%s'
+    identifier_without_vn_nr = ''
+    identifier_with_vn_nr = ''
+    version_nr = None
+
+    def __init__(self):
+        pass
+
+    def is_valid(self):
+        if self.isvalid is None:
+            print("Run process() first")
+            return False
+        return self.isvalid
+
+    def process(self, identifier):
+        # ============================= #
+        # Pre-checks                    #
+        # ============================= #
+        if self.same_version_exists(identifier):
+            self.errorcode = 'preprint_already_submitted'
+            self.isvalid = False
+            return
 
         # Split the given identifier in an article identifier and version number
-        identifier_without_vn_nr = identifier.rpartition('v')[0]
-        arxiv_vn_nr = int(identifier.rpartition('v')[2])
-
-        resubmission = False
-        if previous_submission_undergoing_refereeing(identifier):
-            errormessage = '<p>There exists a preprint with this arXiv identifier '
-                            'but an earlier version number, which is still undergoing '
-                            'peer refereeing.</p>'
-                            '<p>A resubmission can only be performed after request '
-                            'from the Editor-in-charge. Please wait until the '
-                            'closing of the previous refereeing round and '
-                            'formulation of the Editorial Recommendation '
-                            'before proceeding with a resubmission.</p>'
-            return False, errormessage
-
-        # Arxiv query
-        queryurl = ('http://export.arxiv.org/api/query?id_list=%s'
-                    % identifier)
-        arxiv_response = feedparser.parse(queryurl)
+        if re.match("^[0-9]{4,}.[0-9]{4,5}v[0-9]{1,2}$", identifier) is None:
+            self.errorcode = 'bad_identifier'
+            self.isvalid = False
+            return
+
+        self.identifier_without_vn_nr = identifier.rpartition('v')[0]
+        self.identifier_with_vn_nr = identifier
+        self.version_nr = int(identifier.rpartition('v')[2])
+
+        previous_submissions = self.different_versions(self.identifier_without_vn_nr)
+        if previous_submissions:
+            if previous_submissions[0].status == 'revision_requested':
+                resubmission = True
+            else:
+                self.errorcode = 'previous_submission_undergoing_refereeing'
+                self.isvalid = False
+                return
+
+        # ============================= #
+        # Arxiv query                   #
+        # ============================= #
+        queryurl = (self.query_base_url % identifier)
+
+        try:
+            req = requests.get(queryurl, timeout=4.0)
+        except requests.ReadTimeout:
+            self.errorcode = 'arxiv_timeout'
+            self.isvalid = False
+            return
+        except requests.ConnectionError:
+            self.errorcode = 'arxiv_timeout'
+            self.isvalid = False
+            return
+
+        content = req.content
+        arxiv_response = feedparser.parse(content)
 
         # Check if response has at least one entry
-        if not 'entries' in arxiv_response
-            errormessage = 'Bad response from Arxiv.'
-            return False, errormessage
+        if req.status_code == 400 or 'entries' not in arxiv_response:
+            self.errorcode = 'arxiv_bad_request'
+            self.isvalid = False
+            return
+
+        # arxiv_response['entries'][0]['title'] == 'Error'
 
         # Check if preprint exists
-        if not preprint_exists(arxiv_response)
-            errormessage = 'A preprint associated to this identifier does not exist.'
-            return False, errormessage
+        if not self.preprint_exists(arxiv_response):
+            self.errorcode = 'preprint_does_not_exist'
+            self.isvalid = False
+            return
 
         # Check via journal ref if already published
-        arxiv_journal_ref = published_journal_ref
-        if arxiv_journal_ref
-            errormessage = 'This paper has been published as ' + arxiv_journal_ref +
-                            '. You cannot submit it to SciPost anymore.'
-            return False, resubmission
+        self.arxiv_journal_ref = self.published_journal_ref(arxiv_response)
+        if self.arxiv_journal_ref:
+            self.errorcode = 'paper_published_journal_ref'
+            self.isvalid = False
+            return
 
         # Check via DOI if already published
-        arxiv_doi = published_journal_ref
-        if arxiv_doi
-            errormessage = 'This paper has been published under DOI ' + arxiv_doi
-                            + '. You cannot submit it to SciPost anymore.'
-            return False, errormessage
-
-        return arxiv_response, ""
+        self.arxiv_doi = self.published_doi(arxiv_response)
+        if self.arxiv_doi:
+            self.errorcode = 'paper_published_doi'
+            self.isvalid = False
+            return
 
+        self.metadata = arxiv_response
+        self.isvalid = True
+        return
 
-    def same_version_exists(identifier):
+    def same_version_exists(self, identifier):
         return Submission.objects.filter(arxiv_identifier_w_vn_nr=identifier).exists()
 
-    def previous_submission_undergoing_refereeing(identifier):
+    def different_versions(self, identifier):
+        return Submission.objects.filter(
+            arxiv_identifier_wo_vn_nr=identifier).order_by('-arxiv_vn_nr')
+
+    def check_previous_submissions(self, identifier):
         previous_submissions = Submission.objects.filter(
             arxiv_identifier_wo_vn_nr=identifier).order_by('-arxiv_vn_nr')
 
@@ -70,17 +125,17 @@ class ArxivCaller():
         else:
             return False
 
-    def preprint_exists(arxiv_response):
+    def preprint_exists(self, arxiv_response):
         return 'title' in arxiv_response['entries'][0]
 
-    def published_journal_ref(arxiv_response):
-        if 'arxiv_journal_ref' in arxiv_response['entries'][0]
+    def published_journal_ref(self, arxiv_response):
+        if 'arxiv_journal_ref' in arxiv_response['entries'][0]:
             return arxiv_response['entries'][0]['arxiv_journal_ref']
         else:
             return False
 
-    def published_DOI(arxiv_response):
-        if 'arxiv_doi' in arxiv_response['entries'][0]
+    def published_doi(self, arxiv_response):
+        if 'arxiv_doi' in arxiv_response['entries'][0]:
             return arxiv_response['entries'][0]['arxiv_doi']
         else:
             return False
diff --git a/submissions/tests/test_models.py b/submissions/test_models.py
similarity index 100%
rename from submissions/tests/test_models.py
rename to submissions/test_models.py
diff --git a/submissions/test_services.py b/submissions/test_services.py
new file mode 100644
index 0000000000000000000000000000000000000000..58862466fd4e3fd303b553000199acba282e4c61
--- /dev/null
+++ b/submissions/test_services.py
@@ -0,0 +1,44 @@
+from django.test import TestCase
+from .services import ArxivCaller
+import pprint
+
+
+class ArxivCallerTest(TestCase):
+
+    def test_correct_lookup(self):
+        caller = ArxivCaller()
+
+        caller.process('1611.09574v1')
+
+        self.assertEqual(caller.is_valid(), True)
+        self.assertIn('entries', caller.metadata)
+
+    def test_errorcode_for_non_existing_paper(self):
+        caller = ArxivCaller()
+
+        caller.process('2611.09574v1')
+        self.assertEqual(caller.is_valid(), False)
+        self.assertEqual(caller.errorcode, 'preprint_does_not_exist')
+
+    def test_errorcode_for_bad_request(self):
+        caller = ArxivCaller()
+
+        caller.process('161109574v1')
+        self.assertEqual(caller.is_valid(), False)
+        self.assertEqual(caller.errorcode, 'arxiv_bad_request')
+
+    def test_errorcode_for_already_published_journal_ref(self):
+        caller = ArxivCaller()
+
+        caller.process('1412.0006v1')
+        self.assertEqual(caller.is_valid(), False)
+        self.assertEqual(caller.errorcode, 'paper_published_journal_ref')
+        self.assertNotEqual(caller.arxiv_journal_ref, '')
+
+    def test_errorcode_no_version(self):
+        # Should be already caught in form validation
+        caller = ArxivCaller()
+
+        caller.process('1412.0006')
+        self.assertEqual(caller.is_valid(), False)
+        self.assertEqual(caller.errorcode, 'bad_identifier')
diff --git a/submissions/tests/test_views.py b/submissions/test_views.py
similarity index 100%
rename from submissions/tests/test_views.py
rename to submissions/test_views.py
diff --git a/submissions/views.py b/submissions/views.py
index f7a4ac054a33887fecb3f5c76662125ea437275f..c7b9b2e4d7f7c1861a86b45c76e7b027541bd1c7 100644
--- a/submissions/views.py
+++ b/submissions/views.py
@@ -33,6 +33,7 @@ from scipost.utils import Utils
 
 from comments.forms import CommentForm
 
+from .services import ArxivCaller
 
 
 ###############
@@ -44,82 +45,32 @@ def prefill_using_identifier(request):
     if request.method == "POST":
         identifierform = SubmissionIdentifierForm(request.POST)
         if identifierform.is_valid():
-            # Perform Arxiv query and check if results are OK for submission
-            metadata, errormessage = lookup_article(identifierform.cleaned_data['identifier'])
-
-            if not metadata:
-                form = SubmissionForm()
-                return render(request, 'submissions/submit_manuscript.html',
-                              {'identifierform': identifierform, 'form': form,
-                               'errormessage': errormessage})
-
-            is_resubmission = False
-            resubmessage = ''
-            previous_submissions = Submission.objects.filter(
-                arxiv_identifier_wo_vn_nr=identifier_without_vn_nr).order_by('-arxiv_vn_nr')
-            if previous_submissions.exists():
-                # If the Editorial Recommendation hasn't been formulated, ask to wait
-                if previous_submissions[0].status != 'revision_requested':
-                    errormessage = ('<p>There exists a preprint with this arXiv identifier '
-                                    'but an earlier version number, which is still undergoing '
-                                    'peer refereeing.</p>'
-                                    '<p>A resubmission can only be performed after request '
-                                    'from the Editor-in-charge. Please wait until the '
-                                    'closing of the previous refereeing round and '
-                                    'formulation of the Editorial Recommendation '
-                                    'before proceeding with a resubmission.</p>')
-                    return render(request, 'scipost/error.html',
-                                  {'errormessage': mark_safe(errormessage)})
-                is_resubmission = True
-                resubmessage = ('There already exists a preprint with this arXiv identifier '
-                                'but a different version number. \nYour Submission will be '
-                                'handled as a resubmission.')
-            try:
-                queryurl = ('http://export.arxiv.org/api/query?id_list=%s'
-                            % identifierform.cleaned_data['identifier'])
-                arxivquery = feedparser.parse(queryurl)
-                # Flag error if preprint doesn't exist
-                try:
-                    test = arxivquery['entries'][0]['title']
-                except KeyError:
-                    errormessage = 'A preprint associated to this identifier does not exist.'
-                except:
-                    pass
-
-                # If paper has been published, should comment on published version
-                try:
-                    arxiv_journal_ref = arxivquery['entries'][0]['arxiv_journal_ref']
-                    errormessage = ('This paper has been published as ' + arxiv_journal_ref +
-                                    '. You cannot submit it to SciPost anymore.')
-                except:
-                    pass
-                try:
-                    arxiv_doi = arxivquery['entries'][0]['arxiv_doi']
-                    errormessage = ('This paper has been published under DOI ' + arxiv_DOI
-                                    + '. You cannot submit it to SciPost anymore.')
-                except:
-                    pass
-                if errormessage != '':
-                    form = SubmissionForm()
-                    context = {'identifierform': identifierform, 'form': form,
-                               'errormessage': errormessage}
-                    return render(request, 'submissions/submit_manuscript.html', context)
-
-                metadata = arxivquery
-                title = arxivquery['entries'][0]['title']
-                authorlist = arxivquery['entries'][0]['authors'][0]['name']
-                for author in arxivquery['entries'][0]['authors'][1:]:
+            # Use the ArxivCaller class to make the API calls
+            caller = ArxivCaller()
+            caller.process(identifierform.cleaned_data['identifier'])
+
+            if caller.is_valid():
+                # Arxiv response is valid and can be shown
+
+                metadata = caller.metadata
+                is_resubmission = caller.resubmission
+                title = metadata['entries'][0]['title']
+                authorlist = metadata['entries'][0]['authors'][0]['name']
+                for author in metadata['entries'][0]['authors'][1:]:
                     authorlist += ', ' + author['name']
-                arxiv_link = arxivquery['entries'][0]['id']
-                abstract = arxivquery['entries'][0]['summary']
-                initialdata={'is_resubmission': is_resubmission,
-                             'metadata': metadata,
-                             'title': title, 'author_list': authorlist,
-                             'arxiv_identifier_w_vn_nr': identifierform.cleaned_data['identifier'],
-                             'arxiv_identifier_wo_vn_nr': identifier_without_vn_nr,
-                             'arxiv_vn_nr': arxiv_vn_nr,
-                             'arxiv_link': arxiv_link, 'abstract': abstract}
+                arxiv_link = metadata['entries'][0]['id']
+                abstract = metadata['entries'][0]['summary']
+                initialdata = {'is_resubmission': is_resubmission,
+                               'metadata': metadata,
+                               'title': title, 'author_list': authorlist,
+                               'arxiv_identifier_w_vn_nr': caller.identifier_with_vn_nr,
+                               'arxiv_identifier_wo_vn_nr': caller.identifier_without_vn_nr,
+                               'arxiv_vn_nr': caller.version_nr,
+                               'arxiv_link': arxiv_link, 'abstract': abstract}
                 if is_resubmission:
+                    resubmessage = ('There already exists a preprint with this arXiv identifier '
+                                    'but a different version number. \nYour Submission will be '
+                                    'handled as a resubmission.')
                     initialdata['submitted_to_journal'] = previous_submissions[0].submitted_to_journal
                     initialdata['submission_type'] = previous_submissions[0].submission_type
                     initialdata['discipline'] = previous_submissions[0].discipline
@@ -128,17 +79,46 @@ def prefill_using_identifier(request):
                     initialdata['secondary_areas'] = previous_submissions[0].secondary_areas
                     initialdata['referees_suggested'] = previous_submissions[0].referees_suggested
                     initialdata['referees_flagged'] = previous_submissions[0].referees_flagged
+                else:
+                    resubmessage = ''
+
                 form = SubmissionForm(initial=initialdata)
                 context = {'identifierform': identifierform,
                            'form': form,
                            'resubmessage': resubmessage}
                 return render(request, 'submissions/submit_manuscript.html', context)
-            except:
-                print("Unexpected error in prefill_using_identifier:", sys.exc_info()[0])
-                context = {'identifierform': identifierform,
-                           'form': SubmissionForm(),
-                           'errormessage': errormessage,}
-                return render(request, 'submissions/submit_manuscript.html', context)
+
+            else:
+                # Arxiv response is not valid
+                errormessages = {
+                    'preprint_does_not_exist':
+                        'A preprint associated to this identifier does not exist.',
+                    'paper_published_journal_ref':
+                        ('This paper has been published as ' + caller.arxiv_journal_ref +
+                         '. You cannot submit it to SciPost anymore.'),
+                    'paper_published_doi':
+                        ('This paper has been published under DOI ' + caller.arxiv_doi +
+                         '. You cannot submit it to SciPost anymore.'),
+                    'arxiv_timeout': 'Arxiv did not respond in time. Please try again later',
+                    'arxiv_bad_request':
+                        ('There was an error with requesting identifier ' +
+                         caller.identifier_with_vn_nr +
+                         ' from Arxiv. Please check the identifier and try again.'),
+                    'previous_submission_undergoing_refereeing':
+                        ('There exists a preprint with this arXiv identifier '
+                         'but an earlier version number, which is still undergoing '
+                         'peer refereeing.'
+                         'A resubmission can only be performed after request '
+                         'from the Editor-in-charge. Please wait until the '
+                         'closing of the previous refereeing round and '
+                         'formulation of the Editorial Recommendation '
+                         'before proceeding with a resubmission.')
+                }
+
+                identifierform.add_error(None, errormessages[caller.errorcode])
+                form = SubmissionForm()
+                return render(request, 'submissions/submit_manuscript.html',
+                              {'identifierform': identifierform, 'form': form})
         else:
             form = SubmissionForm()
             return render(request, 'submissions/submit_manuscript.html',