diff --git a/packages/component-faraday-selectors/src/index.js b/packages/component-faraday-selectors/src/index.js
index 6508a91a4921237406bd5b9e386e167f1e608977..f1d9bcb1960a84d6656d68c25bf8616b2b4c02a8 100644
--- a/packages/component-faraday-selectors/src/index.js
+++ b/packages/component-faraday-selectors/src/index.js
@@ -7,7 +7,11 @@ export const isHEToManuscript = (state, collectionId) => {
   return get(collection, 'handlingEditor.id') === currentUserId
 }
 
-const canMakeRecommendationStatuses = ['reviewCompleted', 'heAssigned']
+const canMakeRecommendationStatuses = [
+  'reviewCompleted',
+  'heAssigned',
+  'underReview',
+]
 export const canMakeRecommendation = (state, collection, fragment = {}) => {
   if (fragment.id !== last(collection.fragments)) return false
   const isHE = isHEToManuscript(state, collection.id)
@@ -75,13 +79,22 @@ export const canMakeDecision = (state, collection, fragment = {}) => {
   return isEIC && canMakeDecisionStatuses.includes(status)
 }
 
-const canEditManuscriptStatuses = ['draft', 'technicalChecks']
+const canEditManuscriptStatuses = ['draft', 'technicalChecks', 'inQA']
 export const canEditManuscript = (state, collection, fragment = {}) => {
-  if (fragment.id !== last(collection.fragments)) return false
+  const isAdmin = currentUserIs(state, 'isAdmin')
+  if (!isAdmin || fragment.id !== last(collection.fragments)) return false
   const status = get(collection, 'status')
 
+  return canEditManuscriptStatuses.includes(status)
+}
+
+const canOverrideTechnicalChecksStatuses = ['technicalChecks', 'inQA']
+export const canOverrideTechnicalChecks = (state, collection) => {
   const isAdmin = currentUserIs(state, 'isAdmin')
-  return isAdmin && canEditManuscriptStatuses.includes(status)
+  if (!isAdmin) return false
+  const status = get(collection, 'status')
+
+  return canOverrideTechnicalChecksStatuses.includes(status)
 }
 
 export const canSeeReviewersReports = (state, collectionId) => {
diff --git a/packages/component-fixture-manager/src/fixtures/collections.js b/packages/component-fixture-manager/src/fixtures/collections.js
index c6d401815491578a0262f7cb8cb06b2e3ed66c56..84583485feff68c50c532e4a5f4a396147177df2 100644
--- a/packages/component-fixture-manager/src/fixtures/collections.js
+++ b/packages/component-fixture-manager/src/fixtures/collections.js
@@ -11,7 +11,7 @@ const collections = {
     type: 'collection',
     fragments: [fragment.id],
     owners: [user.id],
-    save: jest.fn(),
+    save: jest.fn(() => collections.collection),
     invitations: [
       {
         id: chance.guid(),
@@ -44,6 +44,7 @@ const collections = {
     technicalChecks: {
       token: chance.guid(),
     },
+    status: 'pendingApproval',
   },
 }
 
diff --git a/packages/component-helper-service/src/services/User.js b/packages/component-helper-service/src/services/User.js
index 39d03896853ea00f5bb81425bdda1bb551f7af7f..09c722d31cabe70492fb2c0fcdae381ee4c0c1ef 100644
--- a/packages/component-helper-service/src/services/User.js
+++ b/packages/component-helper-service/src/services/User.js
@@ -72,7 +72,8 @@ class User {
 
   async getEiCName() {
     const editorsInChief = await this.getEditorsInChief()
-    const { firstName, lastName } = editorsInChief[0]
+    const firstName = get(editorsInChief, '0.firstName', 'Editor')
+    const lastName = get(editorsInChief, '0.lastName', 'in Chief')
     return `${firstName} ${lastName}`
   }
 }
diff --git a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/emailCopy.js b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/emailCopy.js
index d4046f5a95f38e0c56bca849133118d98ccbd421..5b3840f79d5c78f1d6abedfb513c89b086f06737 100644
--- a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/emailCopy.js
+++ b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/emailCopy.js
@@ -1,4 +1,5 @@
 const getEmailCopy = ({
+  customId,
   emailType,
   titleText,
   comments = '',
@@ -19,7 +20,6 @@ const getEmailCopy = ({
       break
     case 'author-manuscript-published':
       paragraph = `I am delighted to inform you that ${titleText} has passed through the review process and will be published in Hindawi.<br/><br/>
-    ${comments}<br/><br/>
     Thanks again for choosing to publish with us.`
       hasLink = false
       break
@@ -77,6 +77,9 @@ const getEmailCopy = ({
       paragraph = `In order for ${titleText} to proceed to publication, there needs to be a revision. <br/><br/>
         For more information about what is required, please visit the manuscript details page.`
       break
+    case 'eqa-manuscript-request-for-approval':
+      paragraph = `Manuscript ID ${customId} has passed peer-review and is now ready for EQA. Please click on the link below to either approve or return the manuscript to the Editor in Chief:`
+      break
     default:
       throw new Error(`The ${emailType} email type is not defined.`)
   }
diff --git a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/notifications.js b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/notifications.js
index b3f2e877a4aad364f605e362495d370193328932..c86bbd35a818229fbc82d1992ee27cbe9e91b00e 100644
--- a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/notifications.js
+++ b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/notifications.js
@@ -10,10 +10,12 @@ const {
 
 const { getEmailCopy } = require('./emailCopy')
 
+const editorialAssistantEmail = config.get('mailer.editorialAssistant')
 const unsubscribeSlug = config.get('unsubscribe.url')
 
 module.exports = {
   async sendNotifications({
+    hasEQA,
     baseUrl,
     fragment,
     UserModel,
@@ -33,12 +35,15 @@ module.exports = {
       fragmentAuthors.submittingAuthor.firstName
     } ${fragmentAuthors.submittingAuthor.lastName}`
 
+    const userHelper = new User({ UserModel })
+    const eicName = await userHelper.getEiCName()
+
     const email = new Email({
       type: 'user',
       content: {
         unsubscribeLink: baseUrl,
         ctaText: 'MANUSCRIPT DETAILS',
-        signatureName: get(collection, 'handlingEditor.name', 'N/A'),
+        signatureName: eicName,
         ctaLink: services.createUrl(
           baseUrl,
           `/projects/${collection.id}/versions/${fragment.id}/details`,
@@ -46,78 +51,93 @@ module.exports = {
       },
     })
 
-    const userHelper = new User({ UserModel })
-
-    let comments
-    if (isEditorInChief) {
-      const eicComments = chain(newRecommendation)
-        .get('comments')
-        .find(comm => !comm.public)
-        .get('content')
-        .value()
-
-      comments = eicComments
-    }
-
-    const hasPeerReview = (collection = {}) =>
-      !isEmpty(collection.handlingEditor)
-
     if (
-      (isEditorInChief || newRecommendation.recommendationType === 'review') &&
-      hasPeerReview(collection)
+      !hasEQA &&
+      isEditorInChief &&
+      newRecommendation.recommendation === 'publish'
     ) {
-      // the request came from either the Editor in Chief or a reviewer, so the HE needs to be notified
-      sendHandlingEditorEmail({
+      sendEQAEmail({
         email,
-        eicName: await userHelper.getEiCName(),
+        eicName,
         baseUrl,
-        comments,
-        titleText,
-        targetUserName,
+        collection,
         subjectBaseText,
-        handlingEditor: get(collection, 'handlingEditor', {}),
-        recommendation: newRecommendation.recommendation,
-        recommendationType: newRecommendation.recommendationType,
       })
-    }
-
-    if (
-      newRecommendation.recommendationType !== 'review' &&
-      newRecommendation.recommendation !== 'return-to-handling-editor'
-    ) {
-      if (isEditorInChief || collection.status === 'revisionRequested') {
-        sendAuthorsEmail({
-          email,
-          baseUrl,
-          titleText,
-          parsedFragment,
-          fragmentAuthors,
-          isEditorInChief,
-          subjectBaseText,
-          newRecommendation,
-        })
+    } else {
+      let comments
+      if (isEditorInChief) {
+        const eicComments = chain(newRecommendation)
+          .get('comments')
+          .find(comm => !comm.public)
+          .get('content')
+          .value()
+
+        comments = eicComments
       }
-      if (hasPeerReview(collection)) {
-        sendReviewersEmail({
+
+      const hasPeerReview = (collection = {}) =>
+        !isEmpty(collection.handlingEditor)
+
+      if (
+        (isEditorInChief ||
+          newRecommendation.recommendationType === 'review') &&
+        hasPeerReview(collection)
+      ) {
+        // the request came from either the Editor in Chief or a reviewer, so the HE needs to be notified
+        sendHandlingEditorEmail({
           email,
+          eicName: await userHelper.getEiCName(),
           baseUrl,
-          UserModel,
+          comments,
           titleText,
-          fragmentHelper,
-          isEditorInChief,
+          targetUserName,
           subjectBaseText,
+          handlingEditor: get(collection, 'handlingEditor', {}),
           recommendation: newRecommendation.recommendation,
-          handlingEditorName: get(collection, 'handlingEditor.name', 'N/A'),
+          recommendationType: newRecommendation.recommendationType,
         })
+      }
 
-        sendEiCsEmail({
-          email,
-          baseUrl,
-          userHelper,
-          titleText,
-          subjectBaseText,
-          recommendation: newRecommendation,
-        })
+      if (
+        newRecommendation.recommendationType !== 'review' &&
+        newRecommendation.recommendation !== 'return-to-handling-editor'
+      ) {
+        if (isEditorInChief || collection.status === 'revisionRequested') {
+          sendAuthorsEmail({
+            email,
+            baseUrl,
+            titleText,
+            parsedFragment,
+            fragmentAuthors,
+            isEditorInChief,
+            subjectBaseText,
+            newRecommendation,
+            handlingEditorName: get(collection, 'handlingEditor.name', eicName),
+          })
+        }
+
+        if (hasPeerReview(collection)) {
+          sendReviewersEmail({
+            email,
+            baseUrl,
+            UserModel,
+            titleText,
+            fragmentHelper,
+            isEditorInChief,
+            subjectBaseText,
+            recommendation: newRecommendation.recommendation,
+            handlingEditorName: get(collection, 'handlingEditor.name', eicName),
+          })
+
+          sendEiCsEmail({
+            email,
+            baseUrl,
+            userHelper,
+            titleText,
+            subjectBaseText,
+            recommendation: newRecommendation,
+          })
+        }
       }
     }
   },
@@ -163,7 +183,9 @@ const sendHandlingEditorEmail = ({
   email.content.unsubscribeLink = services.createUrl(baseUrl, unsubscribeSlug, {
     id: handlingEditor.id,
   })
+
   email.content.signatureName = eicName
+
   const { html, text } = email.getBody({
     body: getEmailCopy({
       emailType,
@@ -183,6 +205,7 @@ const sendAuthorsEmail = async ({
   subjectBaseText,
   fragmentAuthors,
   newRecommendation,
+  handlingEditorName,
   parsedFragment: { heRecommendation },
 }) => {
   let emailType, authors, comments
@@ -216,7 +239,10 @@ const sendAuthorsEmail = async ({
     }))
   } else {
     emailType = 'author-request-to-revision'
+
     email.content.subject = `${subjectBaseText} Recommendation`
+    email.content.signatureName = handlingEditorName
+
     const authorNote = newRecommendation.comments.find(comm => comm.public)
     const content = get(authorNote, 'content')
     const authorNoteText = content ? `Reason & Details: "${content}"` : ''
@@ -386,6 +412,43 @@ const sendEiCsEmail = async ({
   })
 }
 
+const sendEQAEmail = ({
+  email,
+  eicName,
+  baseUrl,
+  collection,
+  subjectBaseText,
+}) => {
+  const emailType = 'eqa-manuscript-request-for-approval'
+
+  email.toUser = {
+    email: editorialAssistantEmail,
+    name: 'Editorial Assistant',
+  }
+
+  email.content.unsubscribeLink = baseUrl
+  email.content.signatureName = eicName
+  email.content.subject = `${subjectBaseText} Request for EQA Approval`
+  email.content.ctaLink = services.createUrl(
+    baseUrl,
+    config.get('eqa-decision.url'),
+    {
+      collectionId: collection.id,
+      customId: collection.customId,
+      token: collection.technicalChecks.token,
+    },
+  )
+  email.content.ctaText = 'MAKE DECISION'
+
+  const { html, text } = email.getBody({
+    body: getEmailCopy({
+      emailType,
+      customId: collection.customId,
+    }),
+  })
+  email.sendEmail({ html, text })
+}
+
 const getSubjectByRecommendation = recommendation =>
   ['minor', 'major'].includes(recommendation)
     ? 'Revision Requested'
diff --git a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/post.js b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/post.js
index 69135f088fdff18442320398441a8db3f40562d5..f67754387a6deef1b7dd8f2d93f31221c7bd52d5 100644
--- a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/post.js
+++ b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/post.js
@@ -1,6 +1,7 @@
 const uuid = require('uuid')
-const { pick, get } = require('lodash')
+const { pick, get, set, has } = require('lodash')
 const config = require('config')
+const { v4 } = require('uuid')
 
 const {
   services,
@@ -75,7 +76,10 @@ module.exports = models => async (req, res) => {
       fragment.revision = pick(fragment, ['authors', 'files', 'metadata'])
     }
 
-    if (isEditorInChief && recommendation === 'publish') {
+    const technicalChecks = get(collection, 'technicalChecks', {})
+    const { hasEQA } = technicalChecks
+
+    if (isEditorInChief && recommendation === 'publish' && !hasEQA) {
       const { journal, xmlParser, ftp } = mtsConfig
       const MTS = new MTSService(journal, xmlParser, s3Config, ftp)
       const packageFragment = {
@@ -87,9 +91,28 @@ module.exports = models => async (req, res) => {
       }
 
       await MTS.sendPackage({ fragment: packageFragment, isEQA: true })
+
+      collection.status = 'inQA'
+      set(collection, 'technicalChecks.token', v4())
+      set(collection, 'technicalChecks.hasEQA', false)
+      await collection.save()
+    }
+
+    /* if the EiC returns the manuscript to the HE after the EQA has been performed
+       then remove all properties from the technicalChecks property so that the manuscript
+       can go through the EQA process again
+    */
+    if (
+      isEditorInChief &&
+      recommendation === 'return-to-handling-editor' &&
+      has(collection.technicalChecks, 'hasEQA')
+    ) {
+      collection.technicalChecks = {}
+      await collection.save()
     }
 
     notifications.sendNotifications({
+      hasEQA,
       fragment,
       collection,
       isEditorInChief,
diff --git a/packages/component-manuscript-manager/src/routes/technicalChecks/notifications/emailCopy.js b/packages/component-manuscript-manager/src/routes/technicalChecks/notifications/emailCopy.js
index c562e8be47b57e98d965e88681150adead6057b0..0c36acca52a116cc5f9584d0679a52944e635b02 100644
--- a/packages/component-manuscript-manager/src/routes/technicalChecks/notifications/emailCopy.js
+++ b/packages/component-manuscript-manager/src/routes/technicalChecks/notifications/emailCopy.js
@@ -1,14 +1,34 @@
-const getEmailCopy = ({ emailType, titleText }) => {
+const getEmailCopy = ({ emailType, titleText, comments }) => {
   let paragraph
+  let hasLink = true
   switch (emailType) {
     case 'eqs-manuscript-accepted':
       paragraph = `We are please to inform you that ${titleText} has passed the Hindawi technical check process and is now submitted. Please click the link below to access the manuscript.`
       break
+    case 'he-manuscript-published':
+      hasLink = false
+      paragraph = `Thank you for your recommendation to publish ${titleText} based on the reviews you received.<br/><br/>
+      I can confirm this article will now go through to publication.`
+      break
+    case 'author-manuscript-published':
+      paragraph = `I am delighted to inform you that ${titleText} has passed through the review process and will be published in Hindawi.<br/><br/>
+        Thanks again for choosing to publish with us.`
+      hasLink = false
+      break
+    case 'submitted-reviewers-after-publish':
+      hasLink = false
+      paragraph = `Thank you for your review on ${titleText}. After taking into account the reviews and the recommendation of the Handling Editor, I can confirm this article will now be published.<br/><br/>
+      If you have any queries about this decision, then please email them to Hindawi as soon as possible.`
+      break
+    case 'eqa-manuscript-returned-to-eic':
+      paragraph = `We regret to inform you that ${titleText} has been returned with comments. Please click the link below to access the manuscript.<br/><br/>
+        Comments: ${comments}<br/><br/>`
+      break
     default:
       throw new Error(`The ${emailType} email type is not defined.`)
   }
 
-  return { paragraph, hasLink: true }
+  return { paragraph, hasLink }
 }
 
 module.exports = {
diff --git a/packages/component-manuscript-manager/src/routes/technicalChecks/notifications/notifications.js b/packages/component-manuscript-manager/src/routes/technicalChecks/notifications/notifications.js
index 782cdbb0c0325048800a2f12096f013319fd8b8f..89cc1d71180c06f2fed6c78f2650a974ec8501ea 100644
--- a/packages/component-manuscript-manager/src/routes/technicalChecks/notifications/notifications.js
+++ b/packages/component-manuscript-manager/src/routes/technicalChecks/notifications/notifications.js
@@ -1,3 +1,6 @@
+const config = require('config')
+const { get } = require('lodash')
+
 const {
   User,
   Email,
@@ -6,10 +9,15 @@ const {
 } = require('pubsweet-component-helper-service')
 const { getEmailCopy } = require('./emailCopy')
 
+const unsubscribeSlug = config.get('unsubscribe.url')
+
 module.exports = {
   async sendNotifications({
+    isEQA,
+    agree,
     baseUrl,
     collection,
+    comments = '',
     User: UserModel,
     Fragment: FragmentModel,
   }) {
@@ -18,21 +26,29 @@ module.exports = {
     const parsedFragment = await fragmentHelper.getFragmentData({
       handlingEditor: collection.handlingEditor,
     })
-    const { submittingAuthor } = await fragmentHelper.getAuthorData({
+
+    const {
+      activeAuthors: authors,
+      submittingAuthor,
+    } = await fragmentHelper.getAuthorData({
       UserModel,
     })
 
     const titleText = `the manuscript titled "${parsedFragment.title}" by ${
       submittingAuthor.firstName
     } ${submittingAuthor.lastName}`
+    const subjectBaseText = `${collection.customId}: Manuscript`
 
     const userHelper = new User({ UserModel })
+    const subject = `${subjectBaseText} ${
+      agree ? '' : 'Not '
+    }Passed Technical Checks`
 
     const email = new Email({
       type: 'user',
       content: {
-        subject: `${collection.customId}: Manuscript Passed Technical Checks`,
-        signatureName: 'EQS Team',
+        subject,
+        signatureName: 'EQA Team',
         ctaLink: services.createUrl(
           baseUrl,
           `/projects/${collection.id}/versions/${fragment.id}/details`,
@@ -42,23 +58,173 @@ module.exports = {
       },
     })
 
-    const editors = (await userHelper.getEditorsInChief()).map(eic => ({
-      ...eic,
-      ...getEmailCopy({
-        emailType: 'eqs-manuscript-accepted',
+    if (isEQA && agree) {
+      const eicName = await userHelper.getEiCName()
+      email.content.signatureName = eicName
+
+      sendAuthorsEmail({
+        email,
+        baseUrl,
         titleText,
-      }),
-    }))
-
-    editors.forEach(eic => {
-      email.toUser = {
-        email: eic.email,
-        name: `${eic.firstName} ${eic.lastName}`,
-      }
-      const { html, text } = email.getBody({
-        body: { paragraph: eic.paragraph, hasLink: eic.hasLink },
+        subjectBaseText,
+        fragmentAuthors: authors,
       })
-      email.sendEmail({ html, text })
-    })
+      sendHandlingEditorEmail({
+        email,
+        baseUrl,
+        titleText,
+        subjectBaseText,
+        handlingEditor: get(collection, 'handlingEditor', {}),
+      })
+      sendSubmittedReviewersEmail({
+        email,
+        baseUrl,
+        titleText,
+        UserModel,
+        fragmentHelper,
+        subjectBaseText,
+      })
+    } else {
+      sendEditorsEmail({ email, agree, comments, userHelper, titleText })
+    }
   },
 }
+
+const sendEditorsEmail = async ({
+  email,
+  agree,
+  comments = '',
+  userHelper,
+  titleText,
+}) => {
+  const emailType = agree
+    ? 'eqs-manuscript-accepted'
+    : 'eqa-manuscript-returned-to-eic'
+
+  const editors = (await userHelper.getEditorsInChief()).map(eic => ({
+    ...eic,
+    ...getEmailCopy({
+      emailType,
+      titleText,
+      comments,
+    }),
+  }))
+
+  editors.forEach(eic => {
+    email.toUser = {
+      email: eic.email,
+      name: `${eic.firstName} ${eic.lastName}`,
+    }
+    const { html, text } = email.getBody({
+      body: { paragraph: eic.paragraph, hasLink: eic.hasLink },
+    })
+    email.sendEmail({ html, text })
+  })
+}
+
+const sendHandlingEditorEmail = ({
+  email,
+  baseUrl,
+  titleText,
+  handlingEditor,
+  subjectBaseText,
+}) => {
+  email.content.subject = `${subjectBaseText} Decision`
+  const emailType = 'he-manuscript-published'
+
+  email.toUser = {
+    email: handlingEditor.email,
+    name: handlingEditor.name,
+  }
+  email.content.unsubscribeLink = services.createUrl(baseUrl, unsubscribeSlug, {
+    id: handlingEditor.id,
+  })
+
+  const { html, text } = email.getBody({
+    body: getEmailCopy({
+      emailType,
+      titleText,
+    }),
+  })
+  email.sendEmail({ html, text })
+}
+
+const sendSubmittedReviewersEmail = async ({
+  email,
+  baseUrl,
+  titleText,
+  UserModel,
+  fragmentHelper,
+  subjectBaseText,
+}) => {
+  email.content.subject = `${subjectBaseText} Decision`
+
+  const reviewers = (await fragmentHelper.getReviewers({
+    UserModel,
+    type: 'submitted',
+  })).map(rev => ({
+    ...rev,
+    ...getEmailCopy({
+      emailType: 'submitted-reviewers-after-publish',
+      titleText,
+    }),
+  }))
+
+  reviewers.forEach(reviewer => {
+    email.toUser = {
+      email: reviewer.email,
+      name: `${reviewer.firstName} ${reviewer.lastName}`,
+    }
+    email.content.unsubscribeLink = services.createUrl(
+      baseUrl,
+      unsubscribeSlug,
+      {
+        id: reviewer.id,
+      },
+    )
+    const { html, text } = email.getBody({
+      body: { paragraph: reviewer.paragraph, hasLink: reviewer.hasLink },
+    })
+    email.sendEmail({ html, text })
+  })
+}
+
+const sendAuthorsEmail = ({
+  email,
+  baseUrl,
+  titleText,
+  subjectBaseText,
+  fragmentAuthors,
+}) => {
+  const emailType = 'author-manuscript-published'
+  email.content.subject = `${subjectBaseText} Published`
+
+  const authors = fragmentAuthors.map(author => ({
+    ...author,
+    ...getEmailCopy({
+      emailType,
+      titleText,
+    }),
+  }))
+
+  authors.forEach(author => {
+    email.toUser = {
+      email: author.email,
+      name: `${author.firstName} ${author.lastName}`,
+    }
+    email.content.unsubscribeLink = services.createUrl(
+      baseUrl,
+      unsubscribeSlug,
+      {
+        id: author.id,
+      },
+    )
+    const { html, text } = email.getBody({
+      body: {
+        paragraph: author.paragraph,
+        hasLink: author.hasLink,
+      },
+    })
+    email.sendEmail({ html, text })
+  })
+}
diff --git a/packages/component-manuscript-manager/src/routes/technicalChecks/patch.js b/packages/component-manuscript-manager/src/routes/technicalChecks/patch.js
index 934709a746946699d07062c71084b3013f4fff13..14e68a7cc4b745752a5ddd2d23a733876f0f9a85 100644
--- a/packages/component-manuscript-manager/src/routes/technicalChecks/patch.js
+++ b/packages/component-manuscript-manager/src/routes/technicalChecks/patch.js
@@ -12,13 +12,13 @@ const setNewStatus = (step, agree) => {
   if (step === TECHNICAL_STEPS.EQS) {
     return agree ? 'submitted' : 'rejected'
   } else if (step === TECHNICAL_STEPS.EQA) {
-    return agree ? 'accepted' : 'rejected'
+    return agree ? 'accepted' : 'pendingApproval'
   }
 }
 
 module.exports = ({ Collection, Fragment, User }) => async (req, res) => {
   const { collectionId } = req.params
-  const { token, agree, step } = req.body
+  const { token, agree, step, comments } = req.body
 
   try {
     const collection = await Collection.find(collectionId)
@@ -37,17 +37,21 @@ module.exports = ({ Collection, Fragment, User }) => async (req, res) => {
     }
 
     delete collection.technicalChecks.token
+    if (step === TECHNICAL_STEPS.EQA) {
+      collection.technicalChecks.hasEQA = true
+    }
     collection.status = setNewStatus(step, agree)
     await collection.save()
 
-    if (agree) {
-      sendNotifications({
-        User,
-        Fragment,
-        collection,
-        baseUrl: services.getBaseUrl(req),
-      })
-    }
+    sendNotifications({
+      User,
+      agree,
+      comments,
+      Fragment,
+      collection,
+      baseUrl: services.getBaseUrl(req),
+      isEQA: step === TECHNICAL_STEPS.EQA,
+    })
 
     return res.status(200).json(collection)
   } catch (e) {
diff --git a/packages/component-manuscript-manager/src/tests/fragmentsRecommendations/post.test.js b/packages/component-manuscript-manager/src/tests/fragmentsRecommendations/post.test.js
index 0f0f048e62835ecbd5d6c9df1f36ad3de740b183..686124cb9518df27b9c722fae0f645c764a4d415 100644
--- a/packages/component-manuscript-manager/src/tests/fragmentsRecommendations/post.test.js
+++ b/packages/component-manuscript-manager/src/tests/fragmentsRecommendations/post.test.js
@@ -11,6 +11,7 @@ const chance = new Chance()
 jest.mock('@pubsweet/component-send-email', () => ({
   send: jest.fn(),
 }))
+jest.mock('pubsweet-component-mts-package')
 
 const reqBody = {
   recommendation: 'accept',
@@ -206,4 +207,129 @@ describe('Post fragments recommendations route handler', () => {
     const data = JSON.parse(res._getData())
     expect(data.error).toEqual('Unauthorized.')
   })
+  it('should return success when the EiC recommends to reject without peer review', async () => {
+    const { editorInChief } = testFixtures.users
+    const { collection } = testFixtures.collections
+    const { fragment } = testFixtures.fragments
+    body.recommendation = 'reject'
+    body.recommendationType = 'editorRecommendation'
+
+    delete fragment.recommendations
+    delete fragment.revision
+    delete fragment.invitations
+    delete collection.invitations
+    delete collection.handlingEditor
+
+    const res = await requests.sendRequest({
+      body,
+      userId: editorInChief.id,
+      models,
+      route,
+      path,
+      params: {
+        collectionId: collection.id,
+        fragmentId: fragment.id,
+      },
+    })
+
+    expect(res.statusCode).toBe(200)
+    const data = JSON.parse(res._getData())
+
+    expect(data.userId).toEqual(editorInChief.id)
+    expect(data.recommendation).toBe('reject')
+  })
+  it('should return success when the EiC recommends to publish without EQA', async () => {
+    const { editorInChief } = testFixtures.users
+    const { collection } = testFixtures.collections
+    const { fragment } = testFixtures.fragments
+    body.recommendation = 'publish'
+    body.recommendationType = 'editorRecommendation'
+    delete collection.technicalChecks
+
+    const res = await requests.sendRequest({
+      body,
+      userId: editorInChief.id,
+      models,
+      route,
+      path,
+      params: {
+        collectionId: collection.id,
+        fragmentId: fragment.id,
+      },
+    })
+
+    expect(res.statusCode).toBe(200)
+    const data = JSON.parse(res._getData())
+
+    expect(collection.status).toBe('inQA')
+    expect(collection.technicalChecks).toHaveProperty('hasEQA')
+    expect(collection.technicalChecks.hasEQA).toBeFalsy()
+    expect(data.userId).toEqual(editorInChief.id)
+    expect(data.recommendation).toBe('publish')
+  })
+  it('should return success when the EiC recommends to publish with EQA accepted', async () => {
+    const { editorInChief } = testFixtures.users
+    const { collection } = testFixtures.collections
+    const { fragment } = testFixtures.fragments
+    body.recommendation = 'publish'
+    body.recommendationType = 'editorRecommendation'
+
+    collection.technicalChecks.hasEQA = true
+
+    const res = await requests.sendRequest({
+      body,
+      userId: editorInChief.id,
+      models,
+      route,
+      path,
+      params: {
+        collectionId: collection.id,
+        fragmentId: fragment.id,
+      },
+    })
+
+    expect(res.statusCode).toBe(200)
+    const data = JSON.parse(res._getData())
+
+    expect(collection.status).toBe('accepted')
+    expect(data.userId).toEqual(editorInChief.id)
+    expect(data.recommendation).toBe('publish')
+  })
+  it('should return success when the EiC returns the manuscript to HE with comments after EQA returned to EiC', async () => {
+    const { editorInChief } = testFixtures.users
+    const { collection } = testFixtures.collections
+    const { fragment } = testFixtures.fragments
+    body.recommendation = 'return-to-handling-editor'
+    body.recommendationType = 'editorRecommendation'
+    body.comments = 'This needs more work'
+
+    delete fragment.recommendations
+    delete fragment.revision
+    delete fragment.invitations
+    delete collection.invitations
+    delete collection.handlingEditor
+    collection.technicalChecks.hasEQA = false
+
+    const res = await requests.sendRequest({
+      body,
+      userId: editorInChief.id,
+      models,
+      route,
+      path,
+      params: {
+        collectionId: collection.id,
+        fragmentId: fragment.id,
+      },
+    })
+
+    expect(res.statusCode).toBe(200)
+    const data = JSON.parse(res._getData())
+
+    expect(collection.status).toBe('reviewCompleted')
+    expect(collection.technicalChecks).not.toHaveProperty('token')
+    expect(collection.technicalChecks).not.toHaveProperty('hasEQA')
+
+    expect(data.userId).toEqual(editorInChief.id)
+    expect(data.recommendation).toBe('return-to-handling-editor')
+  })
 })
diff --git a/packages/component-manuscript-manager/src/tests/technicalChecks/patch.test.js b/packages/component-manuscript-manager/src/tests/technicalChecks/patch.test.js
index 37c2ca388c56320be9a1527db7aa22c6f310a002..f8b6ccd6bc92c2817aeb60b454c6347a7d6eb47b 100644
--- a/packages/component-manuscript-manager/src/tests/technicalChecks/patch.test.js
+++ b/packages/component-manuscript-manager/src/tests/technicalChecks/patch.test.js
@@ -29,7 +29,7 @@ describe('Patch technical checks route handler', () => {
     models = Model.build(testFixtures)
   })
 
-  it('should return success when the parameters are correct', async () => {
+  it('should return success when the EQS is accepted', async () => {
     const { collection } = testFixtures.collections
     body.token = collection.technicalChecks.token
 
@@ -46,6 +46,62 @@ describe('Patch technical checks route handler', () => {
     expect(res.statusCode).toBe(200)
   })
 
+  it('should return success when the EQS is rejected', async () => {
+    const { collection } = testFixtures.collections
+    body.token = collection.technicalChecks.token
+    body.agree = false
+
+    const res = await requests.sendRequest({
+      body,
+      models,
+      route,
+      path,
+      params: {
+        collectionId: collection.id,
+      },
+    })
+
+    expect(res.statusCode).toBe(200)
+  })
+
+  it('should return success when the EQA is accepted', async () => {
+    const { collection } = testFixtures.collections
+    body.token = collection.technicalChecks.token
+    body.step = 'eqa'
+
+    const res = await requests.sendRequest({
+      body,
+      models,
+      route,
+      path,
+      params: {
+        collectionId: collection.id,
+      },
+    })
+
+    expect(res.statusCode).toBe(200)
+  })
+
+  it('should return success when the EQA is returned with comments', async () => {
+    const { collection } = testFixtures.collections
+    body.token = collection.technicalChecks.token
+    body.agree = false
+    body.step = 'eqa'
+    body.comments = 'suspicion of plagiarism'
+
+    const res = await requests.sendRequest({
+      body,
+      models,
+      route,
+      path,
+      params: {
+        collectionId: collection.id,
+      },
+    })
+
+    expect(res.statusCode).toBe(200)
+  })
+
   it('should return an error when the collection does not exist', async () => {
     const res = await requests.sendRequest({
       body,
diff --git a/packages/component-manuscript/src/components/SideBarActions.js b/packages/component-manuscript/src/components/SideBarActions.js
index dbfc3d7cd8c6bcbd6f7ce6a70176913185514c9a..ea233bbbc75e697bdfb16c76f7fbdb8c50ed3fcd 100644
--- a/packages/component-manuscript/src/components/SideBarActions.js
+++ b/packages/component-manuscript/src/components/SideBarActions.js
@@ -1,6 +1,6 @@
 import React from 'react'
 import { compose, withHandlers } from 'recompose'
-import { Icon, Button } from '@pubsweet/ui'
+import { Icon } from '@pubsweet/ui'
 import { connect } from 'react-redux'
 import styled from 'styled-components'
 import { th } from '@pubsweet/ui-toolkit'
@@ -15,6 +15,7 @@ import {
   canMakeDecision,
   canMakeRecommendation,
   canEditManuscript,
+  canOverrideTechnicalChecks,
 } from 'pubsweet-component-faraday-selectors/src'
 
 const SideBarActions = ({
@@ -23,26 +24,19 @@ const SideBarActions = ({
   goToEdit,
   canMakeDecision,
   canEditManuscript,
+  goToTechnicalCheck,
+  canOverrideTechChecks,
   canMakeRecommendation,
 }) => (
   <Root>
-    {canEditManuscript && (
-      <Button
-        data-test="button-edit-manuscript"
-        onClick={goToEdit(project, version)}
-        primary
-      >
-        Edit
-      </Button>
-    )}
     {canMakeDecision && (
       <Decision
         collectionId={project.id}
         fragmentId={version.id}
         modalKey={`decide-${version.id}`}
+        status={project.status}
       />
     )}
-
     {canMakeRecommendation && (
       <Recommendation
         collectionId={project.id}
@@ -50,6 +44,24 @@ const SideBarActions = ({
         modalKey={`recommend-${version.id}`}
       />
     )}
+    {canOverrideTechChecks && (
+      <ClickableIcon
+        data-test="button-technical-checks"
+        onClick={goToTechnicalCheck(project)}
+        title="Technical Checks"
+      >
+        <Icon>check-square</Icon>
+      </ClickableIcon>
+    )}
+    {canEditManuscript && (
+      <ClickableIcon
+        data-test="button-edit-manuscript"
+        onClick={goToEdit(project, version)}
+        title="Edit Manuscript"
+      >
+        <Icon>edit</Icon>
+      </ClickableIcon>
+    )}
     <ZipFiles
       archiveName={`ID-${project.customId}`}
       collectionId={project.id}
@@ -68,6 +80,7 @@ export default compose(
     canMakeDecision: canMakeDecision(state, project, version),
     canMakeRecommendation: canMakeRecommendation(state, project, version),
     canEditManuscript: canEditManuscript(state, project, version),
+    canOverrideTechChecks: canOverrideTechnicalChecks(state, project),
   })),
   withHandlers({
     goToEdit: ({ history }) => (project, version) => () => {
@@ -75,6 +88,14 @@ export default compose(
         editMode: true,
       })
     },
+    goToTechnicalCheck: ({ history }) => project => () => {
+      const { status, id, customId, technicalChecks: { token = '' } } = project
+      const stage = status === 'technicalChecks' ? 'eqs' : 'eqa'
+      history.push({
+        pathname: `/${stage}-decision`,
+        search: `?collectionId=${id}&customId=${customId}&token=${token}`,
+      })
+    },
   }),
 )(SideBarActions)
 
diff --git a/packages/component-mts-package/src/PackageManager.js b/packages/component-mts-package/src/PackageManager.js
index 967985f3a45c6170fbd6a4b5d2d627ebe8cac633..b98dbf10308c84b927b10d3f670b285a1b6ca8b7 100644
--- a/packages/component-mts-package/src/PackageManager.js
+++ b/packages/component-mts-package/src/PackageManager.js
@@ -17,30 +17,27 @@ const createFilesPackage = (s3Config, archiver = nodeArchiver) => {
   })
   const s3 = new AWS.S3()
   const asyncGetObject = promisify(s3.getObject.bind(s3))
-  const asyncListObjects = promisify(s3.listObjects.bind(s3))
 
   return async ({ fragment, fileTypes, xmlFile, isEQA = false }) => {
-    const { id } = fragment
+    const { files = {} } = fragment
     let packageName = get(xmlFile, 'name', '').replace('.xml', '')
     if (isEQA) {
       packageName = `ACCEPTED_${packageName}`
     }
     try {
-      const params = {
-        Bucket: s3Config.bucket,
-        Prefix: `${id}`,
-      }
-      const s3Items = await asyncListObjects(params)
-      if (s3Items) {
+      const s3FileIDs = Object.values(files)
+        .reduce((acc, f) => [...acc, ...f], [])
+        .map(f => f.id)
+
+      if (s3FileIDs) {
         const s3Files = await Promise.all(
-          s3Items.Contents.map(content =>
+          s3FileIDs.map(fileID =>
             asyncGetObject({
               Bucket: s3Config.bucket,
-              Key: content.Key,
+              Key: fileID,
             }),
           ),
         )
-
         if (s3Files) {
           const packageOutput = fs.createWriteStream(`${packageName}.zip`)
           const archive = archiver('zip')
diff --git a/packages/component-mts-package/tests/MTS.test.js b/packages/component-mts-package/tests/MTS.test.js
index 6655fbe07f3602b353cb89be4371bde679d4ddff..42c67eafd272402699e9be402e3f9d3f1860e0a6 100644
--- a/packages/component-mts-package/tests/MTS.test.js
+++ b/packages/component-mts-package/tests/MTS.test.js
@@ -27,7 +27,7 @@ describe('MTS integration', () => {
   })
 
   it('should contain configured journal name ', () => {
-    const result = MTS.composeJson(mocks.fragment)
+    const result = MTS.composeJson({ fragment: mocks.fragment })
     expect(result).toHaveProperty(
       'article.front.journal-meta.journal-title-group.journal-title._text',
       'Bioinorganic Chemistry and Applications',
diff --git a/packages/component-user-manager/src/routes/fragmentsUsers/emails/notifications.js b/packages/component-user-manager/src/routes/fragmentsUsers/emails/notifications.js
index 9a7af8dbcd3819870c4d749ba3c85cd910db219b..9a9281fa22b59b1e76db7dcb8cc8ee00b6170641 100644
--- a/packages/component-user-manager/src/routes/fragmentsUsers/emails/notifications.js
+++ b/packages/component-user-manager/src/routes/fragmentsUsers/emails/notifications.js
@@ -13,7 +13,14 @@ const {
 const { getEmailCopy } = require('./emailCopy')
 
 module.exports = {
-  async sendNotifications({ user, baseUrl, fragment, UserModel, collection }) {
+  async sendNotifications({
+    user,
+    baseUrl,
+    fragment,
+    UserModel,
+    collection,
+    reqUser,
+  }) {
     const fragmentHelper = new Fragment({ fragment })
     const { title } = await fragmentHelper.getFragmentData({
       handlingEditor: collection.handlingEditor,
@@ -48,13 +55,16 @@ module.exports = {
       })
     }
 
-    sendAddedToManuscriptEmail({
-      email,
-      baseUrl,
-      user,
-      titleText,
-      subjectBaseText,
-    })
+    const requestUser = await UserModel.find(reqUser)
+    if (requestUser.id !== user.id) {
+      sendAddedToManuscriptEmail({
+        email,
+        baseUrl,
+        user,
+        titleText,
+        subjectBaseText,
+      })
+    }
   },
 }
 
diff --git a/packages/component-user-manager/src/routes/fragmentsUsers/post.js b/packages/component-user-manager/src/routes/fragmentsUsers/post.js
index 6a7546e6f665ef1b7fb295e92c9b14a88ba8a1b8..fa0b2b2f352cd5a03988d3b537dd86b37cd87370 100644
--- a/packages/component-user-manager/src/routes/fragmentsUsers/post.js
+++ b/packages/component-user-manager/src/routes/fragmentsUsers/post.js
@@ -97,6 +97,7 @@ module.exports = models => async (req, res) => {
       baseUrl,
       fragment,
       collection,
+      reqUser: req.user,
       UserModel: models.User,
     })
 
diff --git a/packages/components-faraday/src/components/Dashboard/DashboardCard.js b/packages/components-faraday/src/components/Dashboard/DashboardCard.js
index 044a3a21e91903f72a444097b665d116eac4aff2..d0b8f03d47f45aa1f8a155754152933b970757a5 100644
--- a/packages/components-faraday/src/components/Dashboard/DashboardCard.js
+++ b/packages/components-faraday/src/components/Dashboard/DashboardCard.js
@@ -74,7 +74,6 @@ const DashboardCard = ({
                   collectionId={project.id}
                   fragmentId={version.id}
                   modalKey={`recommend-${version.id}`}
-                  status={project.status}
                 />
               )}
               <ZipFiles
diff --git a/packages/components-faraday/src/components/MakeRecommendation/RecommendWizard.js b/packages/components-faraday/src/components/MakeRecommendation/RecommendWizard.js
index fb7452baf0ba87d8e6d3edb530511df05a9a4bfa..6ad740fde0799055cbc4a8684935b0e37e8b2511 100644
--- a/packages/components-faraday/src/components/MakeRecommendation/RecommendWizard.js
+++ b/packages/components-faraday/src/components/MakeRecommendation/RecommendWizard.js
@@ -9,7 +9,10 @@ import { getFormValues, reset as resetForm } from 'redux-form'
 
 import { FormItems } from '../UIComponents'
 import { StepOne, StepTwo, utils } from './'
-import { createRecommendation } from '../../redux/recommendations'
+import {
+  createRecommendation,
+  selectReviewRecommendations,
+} from '../../redux/recommendations'
 
 const RecommendWizard = ({
   step,
@@ -40,8 +43,9 @@ const RecommendWizard = ({
 
 export default compose(
   connect(
-    state => ({
+    (state, { fragmentId }) => ({
       decision: get(getFormValues('recommendation')(state), 'decision'),
+      reviews: selectReviewRecommendations(state, fragmentId),
     }),
     {
       resetForm,
diff --git a/packages/components-faraday/src/components/MakeRecommendation/StepOne.js b/packages/components-faraday/src/components/MakeRecommendation/StepOne.js
index b6723f9ff0a70dd03fb30668d2e8db606247cd66..1cb644c274d3bf7732c58e245090397fa33f2da6 100644
--- a/packages/components-faraday/src/components/MakeRecommendation/StepOne.js
+++ b/packages/components-faraday/src/components/MakeRecommendation/StepOne.js
@@ -1,5 +1,6 @@
 import React from 'react'
 import { reduxForm } from 'redux-form'
+import { isEmpty } from 'lodash'
 import { RadioGroup, ValidatedField, Button } from '@pubsweet/ui'
 
 import { utils } from './'
@@ -7,7 +8,7 @@ import { FormItems } from '../UIComponents'
 
 const { Row, Title, RowItem, RootContainer, CustomRadioGroup } = FormItems
 
-const StepOne = ({ hideModal, disabled, onSubmit, status }) => (
+const StepOne = ({ hideModal, disabled, onSubmit, reviews }) => (
   <RootContainer>
     <Title>Recommendation for Next Phase</Title>
     <Row>
@@ -21,7 +22,7 @@ const StepOne = ({ hideModal, disabled, onSubmit, status }) => (
               <RadioGroup
                 name="decision"
                 options={
-                  status === 'reviewCompleted'
+                  !isEmpty(reviews)
                     ? utils.recommendationOptions
                     : utils.recommendationOptions.slice(1)
                 }
diff --git a/packages/components-faraday/src/components/UIComponents/EQADecisionPage.js b/packages/components-faraday/src/components/UIComponents/EQADecisionPage.js
new file mode 100644
index 0000000000000000000000000000000000000000..c1fb89f349ec68b04e977988e1e0bfea9a5fda79
--- /dev/null
+++ b/packages/components-faraday/src/components/UIComponents/EQADecisionPage.js
@@ -0,0 +1,231 @@
+import React from 'react'
+import { isEmpty } from 'lodash'
+import { connect } from 'react-redux'
+import { Button } from '@pubsweet/ui'
+import styled from 'styled-components'
+import { th } from '@pubsweet/ui-toolkit'
+import {
+  compose,
+  withState,
+  lifecycle,
+  withHandlers,
+  setDisplayName,
+} from 'recompose'
+
+import {
+  withModal,
+  ConfirmationModal,
+} from 'pubsweet-component-modal/src/components'
+
+import { Err, Subtitle } from './FormItems'
+import { parseSearchParams } from '../utils'
+import {
+  technicalDecision,
+  technicalCheckFetching,
+} from '../../redux/technicalCheck'
+
+const EQADecisionPage = ({
+  params,
+  showEQAModal,
+  errorMessage,
+  successMessage,
+}) => (
+  <Root>
+    <Title>
+      Take a decision for manuscript <b>{params.customId}</b>.
+    </Title>
+    {errorMessage && <Err>{errorMessage}</Err>}
+    {successMessage && <Subtitle>{successMessage}</Subtitle>}
+    {isEmpty(errorMessage) &&
+      isEmpty(successMessage) && (
+        <ButtonContainer>
+          <Button onClick={showEQAModal(false)}>RETURN TO EiC</Button>
+          <Button onClick={showEQAModal(true)} primary>
+            ACCEPT
+          </Button>
+        </ButtonContainer>
+      )}
+  </Root>
+)
+
+const DeclineModal = compose(
+  withState('reason', 'setReason', ''),
+  withHandlers({
+    changeReason: ({ setReason }) => e => {
+      setReason(e.target.value)
+    },
+  }),
+)(({ reason, changeReason, hideModal, onConfirm, modalError }) => (
+  <DeclineRoot>
+    <span>Return Manuscript to Editor in Chief</span>
+    <textarea
+      onChange={changeReason}
+      placeholder="Return reason*"
+      value={reason}
+    />
+    {modalError && <ErrorMessage>{modalError}</ErrorMessage>}
+    <ButtonContainer data-test="eqa-buttons">
+      <Button onClick={hideModal}>Cancel</Button>
+      <Button disabled={!reason} onClick={onConfirm(reason)} primary>
+        Send
+      </Button>
+    </ButtonContainer>
+  </DeclineRoot>
+))
+
+const ModalComponent = ({ type, ...rest }) =>
+  type === 'decline' ? (
+    <DeclineModal {...rest} />
+  ) : (
+    <ConfirmationModal {...rest} />
+  )
+
+export default compose(
+  setDisplayName('EQA Decision page'),
+  connect(
+    state => ({
+      isFetching: technicalCheckFetching(state),
+    }),
+    { technicalDecision },
+  ),
+  withModal(({ isFetching }) => ({
+    isFetching,
+    modalComponent: ModalComponent,
+  })),
+  withState('params', 'setParams', {
+    token: null,
+    customId: null,
+    collectionId: null,
+  }),
+  withState('successMessage', 'setSuccess', ''),
+  lifecycle({
+    componentDidMount() {
+      const { location, setParams } = this.props
+      const { customId, collectionId, token } = parseSearchParams(
+        location.search,
+      )
+      setParams({ customId, collectionId, token })
+    },
+  }),
+  withHandlers({
+    showEQAModal: ({
+      showModal,
+      hideModal,
+      setSuccess,
+      setModalError,
+      technicalDecision,
+      params: { collectionId, token },
+    }) => decision => () => {
+      const acceptConfig = {
+        title: `Are you sure you want to accept this EQA package?`,
+        onConfirm: () => {
+          technicalDecision({
+            step: 'eqa',
+            agree: decision,
+            collectionId,
+            token,
+          }).then(() => {
+            setSuccess(
+              `Manuscript accepted. Thank you for your technical check!`,
+            )
+            hideModal()
+          }, setModalError)
+        },
+        onCancel: hideModal,
+      }
+      const declineConfig = {
+        type: 'decline',
+        title: 'Return Manuscript to Editor in Chief',
+        onConfirm: reason => () => {
+          technicalDecision({
+            step: 'eqa',
+            agree: decision,
+            comments: reason,
+            collectionId,
+            token,
+          }).then(() => {
+            setSuccess(
+              `Manuscript returned with comments. An email has been sent to Editor In Chief. Thank you for your technical check!`,
+            )
+            hideModal()
+          }, setModalError)
+        },
+      }
+
+      const cfg = decision ? acceptConfig : declineConfig
+      showModal(cfg)
+    },
+  }),
+)(EQADecisionPage)
+
+// #region styles
+const Root = styled.div`
+  align-items: center;
+  color: ${th('colorText')};
+  display: flex;
+  flex-direction: column;
+  justify-content: flex-start;
+  margin: 0 auto;
+  text-align: center;
+  width: 70vw;
+
+  a {
+    color: ${th('colorText')};
+  }
+`
+
+const Title = styled.div`
+  color: ${th('colorPrimary')};
+  font-size: ${th('fontSizeHeading5')};
+  font-family: ${th('fontHeading')};
+  margin: 10px auto;
+`
+
+const ButtonContainer = styled.div`
+  align-items: center;
+  display: flex;
+  justify-content: space-around;
+  padding: calc(${th('gridUnit')} / 2);
+  width: calc(${th('gridUnit')} * 15);
+`
+const ErrorMessage = styled.div`
+  color: ${th('colorError')};
+  margin: ${th('subGridUnit')};
+  text-align: center;
+`
+const DeclineRoot = styled.div`
+  align-items: center;
+  background-color: ${th('backgroundColor')};
+  display: flex;
+  flex-direction: column;
+  height: calc(${th('gridUnit')} * 13);
+  justify-content: space-between;
+  padding: calc(${th('subGridUnit')} * 7);
+  width: calc(${th('gridUnit')} * 24);
+
+  & span {
+    color: ${th('colorPrimary')};
+    font-size: ${th('fontSizeHeading5')};
+    font-family: ${th('fontHeading')};
+    margin-bottom: ${th('gridUnit')};
+  }
+
+  & textarea {
+    height: 100%;
+    padding: calc(${th('subGridUnit')} * 2);
+    width: 100%;
+  }
+
+  & textarea:focus,
+  & textarea:active {
+    outline: none;
+  }
+
+  & div {
+    display: flex;
+    justify-content: space-evenly;
+    margin: ${th('gridUnit')} auto 0;
+    width: 100%;
+  }
+`
+// #endregion
diff --git a/packages/components-faraday/src/components/UIComponents/EQSDecisionPage.js b/packages/components-faraday/src/components/UIComponents/EQSDecisionPage.js
index 6aaa02bb30d2245e08ac88c503cbc111651d7c63..165361b6ff2853f62f96dbb9082870a66ed87781 100644
--- a/packages/components-faraday/src/components/UIComponents/EQSDecisionPage.js
+++ b/packages/components-faraday/src/components/UIComponents/EQSDecisionPage.js
@@ -21,7 +21,7 @@ import { Err, Subtitle } from './FormItems'
 import { parseSearchParams } from '../utils'
 import {
   technicalDecision,
-  technicalCheckFetcing,
+  technicalCheckFetching,
 } from '../../redux/technicalCheck'
 
 const EQSDecisionPage = ({
@@ -52,7 +52,7 @@ export default compose(
   setDisplayName('EQS Decision page'),
   connect(
     state => ({
-      isFetching: technicalCheckFetcing(state),
+      isFetching: technicalCheckFetching(state),
     }),
     { technicalDecision },
   ),
diff --git a/packages/components-faraday/src/components/UIComponents/index.js b/packages/components-faraday/src/components/UIComponents/index.js
index a619f97e10cfcf1546e5428b5773ed6e6530e336..ff001b8fb3a18548136a1a88e64816e3cde7a4b8 100644
--- a/packages/components-faraday/src/components/UIComponents/index.js
+++ b/packages/components-faraday/src/components/UIComponents/index.js
@@ -8,5 +8,6 @@ export { default as InfoPage } from './InfoPage'
 export { default as ErrorPage } from './ErrorPage'
 export { default as DateParser } from './DateParser'
 export { default as EQSDecisionPage } from './EQSDecisionPage'
+export { default as EQADecisionPage } from './EQADecisionPage'
 export { default as ConfirmationPage } from './ConfirmationPage'
 export { default as BreadcrumbsHeader } from './BreadcrumbsHeader'
diff --git a/packages/components-faraday/src/redux/technicalCheck.js b/packages/components-faraday/src/redux/technicalCheck.js
index 8cb3a074bf9eed5220f56f7f476a7510cda8dc57..5c8d7b9c2e5125ecfa487aab80cab12234a3c361 100644
--- a/packages/components-faraday/src/redux/technicalCheck.js
+++ b/packages/components-faraday/src/redux/technicalCheck.js
@@ -22,6 +22,7 @@ export const technicalDecision = ({
   step,
   agree,
   token,
+  comments,
   collectionId,
 }) => dispatch => {
   dispatch(decisionRequest())
@@ -29,19 +30,25 @@ export const technicalDecision = ({
     step,
     token,
     agree,
+    comments,
   }).then(
     r => {
       dispatch(decisionSuccess())
       return r
     },
     err => {
-      dispatch(decisionError(err))
-      throw err
+      const errorMessage = get(
+        JSON.parse(err.response),
+        'error',
+        'Oops! Something went wrong!',
+      )
+      dispatch(decisionError(errorMessage))
+      throw errorMessage
     },
   )
 }
 
-export const technicalCheckFetcing = state =>
+export const technicalCheckFetching = state =>
   get(state, 'technicalCheck.fetching', false)
 
 export default (state = {}, action = {}) => {
diff --git a/packages/xpub-faraday/app/routes.js b/packages/xpub-faraday/app/routes.js
index 05e3106ebac869d37c6b1401cf8764def29ab516..e3cb4ba8b9a232317471c34f98ac6f73b3ce92cd 100644
--- a/packages/xpub-faraday/app/routes.js
+++ b/packages/xpub-faraday/app/routes.js
@@ -16,6 +16,7 @@ import {
   InfoPage,
   ErrorPage,
   EQSDecisionPage,
+  EQADecisionPage,
   ConfirmationPage,
 } from 'pubsweet-components-faraday/src/components/UIComponents/'
 import {
@@ -120,6 +121,7 @@ const Routes = () => (
         path="/projects/:project/versions/:version/details"
       />
       <Route component={EQSDecisionPage} exact path="/eqs-decision" />
+      <Route component={EQADecisionPage} exact path="/eqa-decision" />
       <Route component={ErrorPage} exact path="/error-page" />
       <Route component={InfoPage} exact path="/info-page" />
       <Route component={NotFound} />
diff --git a/packages/xpub-faraday/config/default.js b/packages/xpub-faraday/config/default.js
index a39537adc4125ddc1e2327c0b3c7aeeb84d1064d..819278c83b59ebec49ad8628363421503c649948 100644
--- a/packages/xpub-faraday/config/default.js
+++ b/packages/xpub-faraday/config/default.js
@@ -97,6 +97,9 @@ module.exports = {
   'eqs-decision': {
     url: process.env.PUBSWEET_EQS_DECISION || '/eqs-decision',
   },
+  'eqa-decision': {
+    url: process.env.PUBSWEET_EQA_DECISION || '/eqa-decision',
+  },
   unsubscribe: {
     url: process.env.PUBSWEET_UNSUBSCRIBE_URL || '/unsubscribe',
   },
diff --git a/packages/xpub-faraday/config/validations.js b/packages/xpub-faraday/config/validations.js
index 4a96afcddc925807a78fa9495b8be0aa53aedec8..25f2501d38bb6ffaa7619b683bcb3825e28e0883 100644
--- a/packages/xpub-faraday/config/validations.js
+++ b/packages/xpub-faraday/config/validations.js
@@ -13,6 +13,7 @@ module.exports = {
     handlingEditor: Joi.object(),
     technicalChecks: Joi.object({
       token: Joi.string(),
+      hasEQA: Joi.boolean(),
     }),
   },
   fragment: [