diff --git a/packages/component-helper-service/src/services/Fragment.js b/packages/component-helper-service/src/services/Fragment.js
index 1ad57433e23fd430c257f2755f2121df1615104d..09b0e42fa55d4a4493a42260ea3d82c1579ec11e 100644
--- a/packages/component-helper-service/src/services/Fragment.js
+++ b/packages/component-helper-service/src/services/Fragment.js
@@ -21,11 +21,16 @@ class Fragment {
     return owners
   }
 
-  async getFragmentData({ handlingEditor = {} }) {
+  async getFragmentData({ handlingEditor } = {}) {
     const { fragment: { metadata = {}, recommendations = [], id } } = this
-    const heRecommendation = recommendations.find(
-      rec => rec.userId === handlingEditor.id,
-    )
+    let heRecommendation
+
+    if (handlingEditor) {
+      heRecommendation = recommendations.find(
+        rec => rec.userId === handlingEditor.id,
+      )
+    }
+
     let { title = '', abstract = '' } = metadata
     const { type } = metadata
     title = title.replace(/<(.|\n)*?>/g, '')
@@ -73,10 +78,6 @@ class Fragment {
       const userHelper = new User({ UserModel })
       const activeAuthors = await userHelper.getActiveAuthors(authors)
 
-      // const authorsList = activeAuthors.map(
-      //   author => `${author.firstName} ${author.lastName}`,
-      // )
-
       return {
         activeAuthors,
         submittingAuthor,
@@ -97,7 +98,7 @@ class Fragment {
         )
       : invitations.filter(inv => inv.role === role && inv.hasAnswer === false)
 
-    if (type === 'submitting') {
+    if (type === 'submitted') {
       filteredInvitations = filteredInvitations.filter(inv =>
         recommendations.find(
           rec =>
diff --git a/packages/component-helper-service/src/services/email/Email.js b/packages/component-helper-service/src/services/email/Email.js
index fe1714136ddd8f192faa600c2da1250db8c6c5d6..0114386f3fe3fb50627b038012ce165e7eff394c 100644
--- a/packages/component-helper-service/src/services/email/Email.js
+++ b/packages/component-helper-service/src/services/email/Email.js
@@ -13,12 +13,9 @@ class Email {
     },
     content = {
       subject: '',
-      comments: '',
-      titleText: '',
-      timestamp: '',
-      detailsLink: '',
+      ctaLink: '',
+      ctaText: '',
       signatureName: '',
-      sourceUserName: '',
       unsubscribeLink: '',
     },
   }) {
@@ -39,164 +36,32 @@ class Email {
     this.content = newContent
   }
 
-  getBody({ emailType }) {
-    const replacements = {
-      hasLink: true,
-      toUserName: this.toUser.name,
-      beforeAnchor: 'Please visit the',
-      afterAnchor: 'to see the full review',
-      detailsLink: this.content.detailsLink,
-      signatureName: this.content.signatureName,
-      unsubscribeLink: this.content.unsubscribeLink,
-    }
-    switch (emailType) {
-      case 'unassign-reviewer':
-        replacements.paragraph = `You are no longer needed to review ${
-          this.content.titleText
-        }. If you have comments on this manuscript you believe the Editor should
-          see, please email them to ${config.get(
-            'mailer.from',
-          )} as soon as possible. Thank you for your
-          time and I hope you will consider reviewing for Hindawi again.`
-        break
-      case 'review-submitted':
-        replacements.paragraph = `We are pleased to inform you that Dr. ${
-          this.content.sourceUserName
-        } has submitted a review for ${this.content.titleText}.`
-        break
-      case 'reviewer-agreed':
-        // subject = `${meta.collection.customId}: Manuscript Reviews`
-        replacements.paragraph = `We are pleased to inform you that Dr. ${
-          this.content.sourceUserName
-        } has agreed to review ${this.content.titleText}. <br/>
-        You should receive the report by Dr. ${
-          this.content.sourceUserName
-        } before ${helpers.getExpectedDate(this.content.timestamp, 14)}.`
-        replacements.beforeAnchor =
-          'If you have any queries, or would like to send a reminder if you no report has been submitted, then please visit the'
-        break
-      case 'reviewer-declined':
-        // subject = `${meta.collection.customId}: Manuscript Reviews`
-        replacements.paragraph = `We regret to inform you that Dr. ${
-          this.content.sourceUserName
-        } has declined to review ${this.content.titleText}.`
-        replacements.afterAnchor =
-          'to see if you need to invite any additional reviewers in order to reach a decision on the manuscript'
-        break
-      case 'reviewer-thank-you':
-        // subject = `${meta.collection.customId}: Manuscript Review`
-        replacements.paragraph = `Thank you for agreeing to review ${
-          this.content.titleText
-        }.`
-        replacements.beforeAnchor =
-          'You can view the full PDF file of the manuscript and post your review report using the following URL:'
-        replacements.afterAnchor = ''
-        break
-      case 'agreed-reviewers-after-he-recommendation':
-        replacements.hasLink = false
-        replacements.paragraph = `I appreciate any time you may have spent reviewing ${
-          this.content.titleText
-        }. However, an editorial decision has been made and the review of this manuscript is now complete. I apologize for any inconvenience. <br/>
-        If you have comments on this manuscript you believe the Editor should see, please email them to Hindawi as soon as possible. <br/>
-        Thank you for your interest and I hope you will consider reviewing for Hindawi again.`
-        break
-      case 'pending-reviewers-after-he-recommendation':
-        replacements.hasLink = false
-
-        replacements.paragraph = `An editorial decision has been made regarding ${
-          this.content.titleText
-        }. So, you do not need to proceed with the review of this manuscript. <br/><br/>
-        If you have comments on this manuscript you believe the Editor should see, please email them to Hindawi as soon as possible.`
-        break
-      case 'eic-recommendation':
-        // subject = `${meta.collection.customId}: Manuscript Recommendation`
-        replacements.beforeAnchor =
-          'For more information about what is required, please visit the '
-        break
-      case 'author-request-to-revision':
-        replacements.paragraph = `In order for ${
-          this.content.titleText
-        } to proceed to publication, there needs to be a revision. <br/><br/>
-        ${this.content.comments}<br/><br/>`
-        replacements.beforeAnchor =
-          'For more information about what is required, please visit the '
-        break
-      case 'author-manuscript-rejected':
-        replacements.paragraph = `I am sorry to inform you that ${
-          this.content.titleText
-        } has been rejected for publication. <br/><br/>
-        ${this.content.comments}<br/><br/>`
-        replacements.hasLink = false
-        break
-      case 'author-manuscript-published':
-        replacements.paragraph = `I am delighted to inform you that ${
-          this.content.titleText
-        } has passed through the review process and will be published in Hindawi.<br/><br/>
-        ${this.content.comments}<br/><br/>
-        Thanks again for choosing to publish with us.`
-        replacements.hasLink = false
-        break
-      case 'he-manuscript-rejected':
-        // subject = meta.emailSubject
-        replacements.hasLink = false
-        replacements.paragraph = `Thank you for your recommendation to reject ${
-          this.content.titleText
-        } based on the reviews you received.<br/><br/>
-        I can confirm this article has now been rejected.`
-        break
-      case 'he-manuscript-published':
-        replacements.hasLink = false
-        replacements.paragraph = `Thank you for your recommendation to publish ${
-          this.content.titleText
-        } based on the reviews you received.<br/><br/>
-        I can confirm this article will now go through to publication.`
-        break
-      case 'he-manuscript-return-with-comments':
-        // subject = meta.emailSubject
-        replacements.hasLink = false
-        replacements.paragraph = `Thank you for your recommendation for ${
-          this.content.titleText
-        } based on the reviews you received.<br/><br/>
-        ${this.content.comments}<br/><br/>`
-        break
-      case 'submitting-reviewers-after-decision':
-        replacements.hasLink = false
-        replacements.paragraph = `Thank you for your review on ${
-          this.content.titleText
-        }. After taking into account the reviews and the recommendation of the Handling Editor, I can confirm this article ${
-          this.content.comments
-        }.<br/><br/>
-        If you have any queries about this decision, then please email them to Hindawi as soon as possible.`
-        break
-      case 'new-version-submitted':
-        replacements.paragraph = `A new version of ${
-          this.content.titleText
-        } has been submitted.`
-        replacements.beforeAnchor =
-          'Previous reviewers have been automatically invited to review the manuscript again. Please visit the'
-        replacements.afterAnchor =
-          'to see the latest version and any other actions you may need to take'
-        break
-      case 'submitting-reviewers-after-revision':
-        replacements.paragraph = `A new version of ${
-          this.content.titleText
-        } has been submitted.`
-        replacements.beforeAnchor = `As you have reviewed the previous version of this manuscript, I would be grateful if you can review this revised version and submit a review report by ${helpers.getExpectedDate(
-          this.content.timestamp,
-          14,
-        )}. You can download the PDF of the revised version and submit your new review from the following URL:`
-        break
-      default:
-        throw new Error(`undefined email type: ${emailType}`)
+  getBody({ body = {}, hasLink = true, isReviewerInvitation = false }) {
+    if (isReviewerInvitation) {
+      return {
+        html: helpers.getInvitationBody({
+          replacements: {
+            toUserName: this.toUser.name,
+            ...this.content,
+            ...body,
+          },
+        }),
+        text: `${this.content.signatureName}`,
+      }
     }
 
     return {
-      html: helpers.getNotificationBody('notification', replacements),
-      text: `${replacements.intro} ${replacements.paragraph} ${
-        replacements.beforeAnchor
-      } ${replacements.detailsUrl} ${replacements.afterAnchor} ${
-        replacements.signatureName
-      }`,
+      html: helpers.getNotificationBody({
+        replacements: {
+          hasLink,
+          paragraph: body.paragraph,
+          toUserName: this.toUser.name,
+          ...this.content,
+        },
+      }),
+      text: `${body.paragraph} ${this.content.ctaLink} ${
+        this.content.ctaText
+      } ${this.content.signatureName}`,
     }
   }
 
diff --git a/packages/component-helper-service/src/services/email/helpers.js b/packages/component-helper-service/src/services/email/helpers.js
index d2a0802616d2c8afa7c7e9ba817dcc25261b65c3..4a8559e128c3de4b020f910fc8a55022eba598a1 100644
--- a/packages/component-helper-service/src/services/email/helpers.js
+++ b/packages/component-helper-service/src/services/email/helpers.js
@@ -1,81 +1,27 @@
-const querystring = require('querystring')
+// const querystring = require('querystring')
 const fs = require('fs')
 const handlebars = require('handlebars')
 
-const createUrl = (baseUrl, slug, queryParams = null) =>
-  !queryParams
-    ? `${baseUrl}${slug}`
-    : `${baseUrl}${slug}?${querystring.encode(queryParams)}`
-
-const getEmailBody = (emailType, replacements) => {
+const getNotificationBody = ({ replacements }) => {
   handlePartial('header', replacements)
   handlePartial('footer', replacements)
-  handlePartial('mainButton', replacements)
-  handlePartial('mainBody', replacements)
-
-  return getMainTemplate(emailType, replacements)
-}
-
-const getNotificationBody = (emailType, replacements) => {
-  handlePartial('notificationHeader', replacements)
-  handlePartial('footer', replacements)
   handlePartial('signature', replacements)
-  if (replacements.hasLink) handlePartial('manuscriptDetailsLink', replacements)
-  handlePartial('notificationBody', replacements)
+  if (replacements.hasLink) handlePartial('button', replacements)
+  handlePartial('body', replacements)
 
-  return getMainTemplate(emailType, replacements)
+  return getMainTemplate({ fileName: 'notification', context: replacements })
 }
 
-const getInvitationBody = (emailType, replacements) => {
-  handlePartial('invitationHeader', replacements)
+const getInvitationBody = ({ replacements }) => {
+  handlePartial('invHeader', replacements)
   handlePartial('footer', replacements)
-  handlePartial('invitationUpperContent', replacements)
-  handlePartial('invitationButtons', replacements)
-  handlePartial('manuscriptData', replacements)
+  handlePartial('invUpperContent', replacements)
+  handlePartial('invButtons', replacements)
+  handlePartial('invManuscriptData', replacements)
   handlePartial('signature', replacements)
-  handlePartial('invitationLowerContent', replacements)
+  handlePartial('invLowerContent', replacements)
 
-  return getMainTemplate(emailType, replacements)
-}
-
-const getBody = (emailType, replacements) => {
-  const simplePartials = ['header', 'footer', 'mainButton', 'mainBody']
-  const notificationPartials = [
-    'notificationHeader',
-    'footer',
-    'signature',
-    'manuscriptDetailsLink',
-    'notificationBody',
-  ]
-  const invitationPartials = [
-    'invitationHeader',
-    'footer',
-    'invitationUpperContent',
-    'invitationButtons',
-    'manuscriptData',
-    'signature',
-    'invitationLowerContent',
-  ]
-
-  switch (emailType) {
-    case 'simpleCTA':
-    case 'noCTA':
-      simplePartials.forEach(partial => handlePartial(partial, replacements))
-      break
-    case 'invitation':
-      invitationPartials.forEach(partial =>
-        handlePartial(partial, replacements),
-      )
-      break
-    case 'notification':
-      notificationPartials.forEach(partial =>
-        handlePartial(partial, replacements),
-      )
-      break
-    default:
-      break
-  }
-  return getMainTemplate(emailType, replacements)
+  return getMainTemplate({ fileName: 'invitation', context: replacements })
 }
 
 const readFile = path =>
@@ -94,30 +40,14 @@ const handlePartial = (partialName = 'signature', context = {}) => {
   handlebars.registerPartial(partialName, partial)
 }
 
-const getMainTemplate = (fileName, context) => {
+const getMainTemplate = ({ fileName, context }) => {
   const htmlFile = readFile(`${__dirname}/templates/${fileName}.html`)
   const htmlTemplate = handlebars.compile(htmlFile)
   const htmlBody = htmlTemplate(context)
   return htmlBody
 }
 
-const getExpectedDate = (timestamp, daysExpected) => {
-  const date = new Date(timestamp)
-  let expectedDate = date.getDate() + daysExpected
-  date.setDate(expectedDate)
-  expectedDate = date.toLocaleDateString('en-US', {
-    day: 'numeric',
-    month: 'long',
-    year: 'numeric',
-  })
-  return expectedDate
-}
-
 module.exports = {
-  getBody,
-  createUrl,
-  getEmailBody,
-  getExpectedDate,
   getNotificationBody,
   getInvitationBody,
 }
diff --git a/packages/component-helper-service/src/services/email/templates/invitation.html b/packages/component-helper-service/src/services/email/templates/invitation.html
index e48b106ecb4b622b0131103e70f7caa86fe1fbe4..f9d5ed18cfa96454ba3454e9555e6144a6411467 100644
--- a/packages/component-helper-service/src/services/email/templates/invitation.html
+++ b/packages/component-helper-service/src/services/email/templates/invitation.html
@@ -1,5 +1,5 @@
-{{> invitationHeader }}
-{{> invitationUpperContent }}
-{{> invitationButtons }}
-{{> invitationLowerContent }}
+{{> invHeader }}
+{{> invUpperContent }}
+{{> invButtons }}
+{{> invLowerContent }}
 {{> footer }}
\ No newline at end of file
diff --git a/packages/component-helper-service/src/services/email/templates/noCTA.html b/packages/component-helper-service/src/services/email/templates/noCTA.html
deleted file mode 100644
index 63214091779bd60eac26f4f52433156083f5033f..0000000000000000000000000000000000000000
--- a/packages/component-helper-service/src/services/email/templates/noCTA.html
+++ /dev/null
@@ -1,3 +0,0 @@
-{{> header }}
-{{> mainBody }}
-{{> footer }}
diff --git a/packages/component-helper-service/src/services/email/templates/notification.html b/packages/component-helper-service/src/services/email/templates/notification.html
index 56554d0f77a46d29e2ecddae448d48c2176c5ce3..3576bee8f1b0f5edd6bb1414e4f68eb61f0fff40 100644
--- a/packages/component-helper-service/src/services/email/templates/notification.html
+++ b/packages/component-helper-service/src/services/email/templates/notification.html
@@ -1,3 +1,6 @@
-{{> notificationHeader}}
-{{> notificationBody}}
+{{> header }}
+{{> body }}
+{{#if hasLink }}
+  {{> button }}
+{{/if}}
 {{> footer}}
\ No newline at end of file
diff --git a/packages/component-helper-service/src/services/email/templates/partials/notificationBody.hbs b/packages/component-helper-service/src/services/email/templates/partials/body.hbs
similarity index 85%
rename from packages/component-helper-service/src/services/email/templates/partials/notificationBody.hbs
rename to packages/component-helper-service/src/services/email/templates/partials/body.hbs
index 310722e99b26d50e269da57bf0f3c8b7023cc580..30baf1925dd48c8953c7ade58516ede89ec927e7 100644
--- a/packages/component-helper-service/src/services/email/templates/partials/notificationBody.hbs
+++ b/packages/component-helper-service/src/services/email/templates/partials/body.hbs
@@ -6,9 +6,6 @@
         <p>&nbsp;</p>
         <p>
           {{{paragraph}}}
-          {{#if hasLink }}
-            {{> manuscriptDetailsLink}}
-          {{/if}}
         </p>
         <p>&nbsp;</p>
         {{> signature}}
diff --git a/packages/component-helper-service/src/services/email/templates/partials/mainButton.hbs b/packages/component-helper-service/src/services/email/templates/partials/button.hbs
similarity index 100%
rename from packages/component-helper-service/src/services/email/templates/partials/mainButton.hbs
rename to packages/component-helper-service/src/services/email/templates/partials/button.hbs
diff --git a/packages/component-helper-service/src/services/email/templates/partials/header.hbs b/packages/component-helper-service/src/services/email/templates/partials/header.hbs
index 3e8efa3eaeff420f3bbf0e68bc88d48713410851..a62d4be742baba10db155a84f6db8e6535880c7b 100644
--- a/packages/component-helper-service/src/services/email/templates/partials/header.hbs
+++ b/packages/component-helper-service/src/services/email/templates/partials/header.hbs
@@ -145,7 +145,7 @@
                                 width="100%" style="display: none !important; mso-hide: all; visibility: hidden; opacity: 0; color: transparent; height: 0; width: 0;">
                                 <tr>
                                   <td role="module-content">
-                                    <p>{{ previewText }}</p>
+                                    <p>you have a new notification</p>
                                   </td>
                                 </tr>
                               </table>
diff --git a/packages/component-helper-service/src/services/email/templates/partials/invitationButtons.hbs b/packages/component-helper-service/src/services/email/templates/partials/invButtons.hbs
similarity index 96%
rename from packages/component-helper-service/src/services/email/templates/partials/invitationButtons.hbs
rename to packages/component-helper-service/src/services/email/templates/partials/invButtons.hbs
index 002013ea2b7fa1e76bf6441fed608f79d0a8c99b..5c5041dec3a973c019e5743106826fa11137c14e 100644
--- a/packages/component-helper-service/src/services/email/templates/partials/invitationButtons.hbs
+++ b/packages/component-helper-service/src/services/email/templates/partials/invButtons.hbs
@@ -27,7 +27,7 @@
                         <tr>
                           <td align="center" bgcolor="#0d78f2" class="inner-td" style="border-radius:6px;font-size:16px;text-align:center;background-color:inherit">
                             <a style="background-color:#0d78f2;border:1px solid #333333;border-color:#0d78f2;border-radius:0px;border-width:1px;color:#ffffff;display:inline-block;font-family:arial,helvetica,sans-serif;font-size:16px;font-weight:normal;letter-spacing:0px;line-height:16px;padding:12px 18px 12px 18px;text-align:center;text-decoration:none"
-                              href="{{agreeUrl}}" target="_blank">AGREE</a>
+                              href="{{ agreeLink }}" target="_blank">AGREE</a>
                           </td>
                         </tr>
                       </tbody>
@@ -62,7 +62,7 @@
                         <tr>
                           <td align="center" bgcolor="#e4dfdf" class="inner-td" style="border-radius:6px;font-size:16px;text-align:center;background-color:inherit">
                             <a style="background-color:#e4dfdf;border:1px solid #333333;border-color:#E4DFDF;border-radius:0px;border-width:1px;color:#302e2e;display:inline-block;font-family:arial,helvetica,sans-serif;font-size:16px;font-weight:normal;letter-spacing:0px;line-height:16px;padding:12px 18px 12px 18px;text-align:center;text-decoration:none"
-                              href="{{declineUrl}}" target="_blank">DECLINE</a>
+                              href="{{ declineLink }}" target="_blank">DECLINE</a>
                           </td>
                         </tr>
                       </tbody>
diff --git a/packages/component-helper-service/src/services/email/templates/partials/invitationHeader.hbs b/packages/component-helper-service/src/services/email/templates/partials/invHeader.hbs
similarity index 98%
rename from packages/component-helper-service/src/services/email/templates/partials/invitationHeader.hbs
rename to packages/component-helper-service/src/services/email/templates/partials/invHeader.hbs
index 3e8efa3eaeff420f3bbf0e68bc88d48713410851..a8390f81f0389272c8824e79e17fda96b444748d 100644
--- a/packages/component-helper-service/src/services/email/templates/partials/invitationHeader.hbs
+++ b/packages/component-helper-service/src/services/email/templates/partials/invHeader.hbs
@@ -145,7 +145,7 @@
                                 width="100%" style="display: none !important; mso-hide: all; visibility: hidden; opacity: 0; color: transparent; height: 0; width: 0;">
                                 <tr>
                                   <td role="module-content">
-                                    <p>{{ previewText }}</p>
+                                    <p>new invitation</p>
                                   </td>
                                 </tr>
                               </table>
diff --git a/packages/component-helper-service/src/services/email/templates/partials/invitationLowerContent.hbs b/packages/component-helper-service/src/services/email/templates/partials/invLowerContent.hbs
similarity index 84%
rename from packages/component-helper-service/src/services/email/templates/partials/invitationLowerContent.hbs
rename to packages/component-helper-service/src/services/email/templates/partials/invLowerContent.hbs
index ef60e6b2aa6d9d303515dfc6feead9c054c30cc6..05a44b844d5fbd75da38c1864a74e42ecdae399e 100644
--- a/packages/component-helper-service/src/services/email/templates/partials/invitationLowerContent.hbs
+++ b/packages/component-helper-service/src/services/email/templates/partials/invLowerContent.hbs
@@ -2,12 +2,12 @@
   <tr>
     <td style="padding:30px 23px 0px 23px;background-color:#ffffff;" height="100%" valign="top" bgcolor="#ffffff">
       <p data-pm-slice="1 1 []">
-        <a href="{{ manuscriptDetailsUrl }}">See more information</a>
+        <a href="{{ detailsLink }}">See more information</a>
       </p>
 
       <p data-pm-slice="1 1 []">&nbsp;</p>
 
-      {{> manuscriptData }}
+      {{> invManuscriptData }}
       <p data-pm-slice="1 1 []">{{{ lowerContent }}}</p>
 
       <p>&nbsp;</p>
diff --git a/packages/component-helper-service/src/services/email/templates/partials/manuscriptData.hbs b/packages/component-helper-service/src/services/email/templates/partials/invManuscriptData.hbs
similarity index 100%
rename from packages/component-helper-service/src/services/email/templates/partials/manuscriptData.hbs
rename to packages/component-helper-service/src/services/email/templates/partials/invManuscriptData.hbs
diff --git a/packages/component-helper-service/src/services/email/templates/partials/invitationUpperContent.hbs b/packages/component-helper-service/src/services/email/templates/partials/invUpperContent.hbs
similarity index 85%
rename from packages/component-helper-service/src/services/email/templates/partials/invitationUpperContent.hbs
rename to packages/component-helper-service/src/services/email/templates/partials/invUpperContent.hbs
index 1bacf2e791241303b5242c62b5f2393a6dc43930..c32a513a9541d234ae3d5ed01bcae96824f728a0 100644
--- a/packages/component-helper-service/src/services/email/templates/partials/invitationUpperContent.hbs
+++ b/packages/component-helper-service/src/services/email/templates/partials/invUpperContent.hbs
@@ -2,7 +2,7 @@
   <tr>
     <td style="padding:30px 23px 20px 23px;background-color:#ffffff;" height="100%" valign="top" bgcolor="#ffffff">
       <div>
-        <p data-pm-slice="1 1 []">{{ intro }},</p>
+        <p data-pm-slice="1 1 []">Dear Dr. {{ toUserName }},</p>
 
         <p>&nbsp;</p>
         <p>{{ upperContent }}</p>
diff --git a/packages/component-helper-service/src/services/email/templates/partials/mainBody.hbs b/packages/component-helper-service/src/services/email/templates/partials/mainBody.hbs
deleted file mode 100644
index 6fb579666eab6f2477f7d40e50f7d563fa47bb80..0000000000000000000000000000000000000000
--- a/packages/component-helper-service/src/services/email/templates/partials/mainBody.hbs
+++ /dev/null
@@ -1,10 +0,0 @@
-<table class="module" role="module" data-type="text" border="0" cellpadding="0" cellspacing="0" width="100%" style="table-layout: fixed;">
-  <tr>
-    <td style="padding:30px 23px 0px 23px;background-color:#ffffff;" height="100%" valign="top" bgcolor="#ffffff">
-      <h1 style="text-align: center;">{{ headline }}</h1>
-      <div style="text-align: center;">{{ paragraph }}</div>
-      <div style="text-align: center;">&nbsp;</div>
-      <div style="text-align: center;">&nbsp;</div>
-    </td>
-  </tr>
-</table>
\ No newline at end of file
diff --git a/packages/component-helper-service/src/services/email/templates/partials/manuscriptDetailsLink.hbs b/packages/component-helper-service/src/services/email/templates/partials/manuscriptDetailsLink.hbs
deleted file mode 100644
index f1ec72bb255dfe7c352e5641b37bbabb9b44e26b..0000000000000000000000000000000000000000
--- a/packages/component-helper-service/src/services/email/templates/partials/manuscriptDetailsLink.hbs
+++ /dev/null
@@ -1 +0,0 @@
- {{ beforeAnchor }} <a href="{{ detailsLink }}">manuscript details page</a> {{ afterAnchor}}.
\ No newline at end of file
diff --git a/packages/component-helper-service/src/services/email/templates/partials/notificationHeader.hbs b/packages/component-helper-service/src/services/email/templates/partials/notificationHeader.hbs
deleted file mode 100644
index a62d4be742baba10db155a84f6db8e6535880c7b..0000000000000000000000000000000000000000
--- a/packages/component-helper-service/src/services/email/templates/partials/notificationHeader.hbs
+++ /dev/null
@@ -1,161 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html data-editor-version="2" class="sg-campaigns" xmlns="http://www.w3.org/1999/xhtml">
-
-<head>
-  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-  <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1" />
-  <!--[if !mso]><!-->
-  <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
-  <!--<![endif]-->
-  <!--[if (gte mso 9)|(IE)]>
-    <xml>
-    <o:OfficeDocumentSettings>
-    <o:AllowPNG/>
-    <o:PixelsPerInch>96</o:PixelsPerInch>
-    </o:OfficeDocumentSettings>
-    </xml>
-    <![endif]-->
-  <!--[if (gte mso 9)|(IE)]>
-    <style type="text/css">
-      body {width: 600px;margin: 0 auto;}
-      table {border-collapse: collapse;}
-      table, td {mso-table-lspace: 0pt;mso-table-rspace: 0pt;}
-      img {-ms-interpolation-mode: bicubic;}
-    </style>
-    <![endif]-->
-
-  <style type="text/css">
-    body,
-    p,
-    div {
-      font-family: helvetica, arial, sans-serif;
-      font-size: 14px;
-    }
-
-    body {
-      color: #626262;
-    }
-
-    body a {
-      color: #0D78F2;
-      text-decoration: none;
-    }
-
-    p {
-      margin: 0;
-      padding: 0;
-    }
-
-    table.wrapper {
-      width: 100% !important;
-      table-layout: fixed;
-      -webkit-font-smoothing: antialiased;
-      -webkit-text-size-adjust: 100%;
-      -moz-text-size-adjust: 100%;
-      -ms-text-size-adjust: 100%;
-    }
-
-    img.max-width {
-      max-width: 100% !important;
-    }
-
-    .column.of-2 {
-      width: 50%;
-    }
-
-    .column.of-3 {
-      width: 33.333%;
-    }
-
-    .column.of-4 {
-      width: 25%;
-    }
-
-    @media screen and (max-width:480px) {
-      .preheader .rightColumnContent,
-      .footer .rightColumnContent {
-        text-align: left !important;
-      }
-      .preheader .rightColumnContent div,
-      .preheader .rightColumnContent span,
-      .footer .rightColumnContent div,
-      .footer .rightColumnContent span {
-        text-align: left !important;
-      }
-      .preheader .rightColumnContent,
-      .preheader .leftColumnContent {
-        font-size: 80% !important;
-        padding: 5px 0;
-      }
-      table.wrapper-mobile {
-        width: 100% !important;
-        table-layout: fixed;
-      }
-      img.max-width {
-        height: auto !important;
-        max-width: 480px !important;
-      }
-      a.bulletproof-button {
-        display: block !important;
-        width: auto !important;
-        font-size: 80%;
-        padding-left: 0 !important;
-        padding-right: 0 !important;
-      }
-      .columns {
-        width: 100% !important;
-      }
-      .column {
-        display: block !important;
-        width: 100% !important;
-        padding-left: 0 !important;
-        padding-right: 0 !important;
-        margin-left: 0 !important;
-        margin-right: 0 !important;
-      }
-    }
-  </style>
-  <!--user entered Head Start-->
-
-  <!--End Head user entered-->
-</head>
-
-<body>
-  <center class="wrapper" data-link-color="#0D78F2" data-body-style="font-size: 14px; font-family: helvetica,arial,sans-serif; color: #626262; background-color: #F4F4F4;">
-    <div class="webkit">
-      <table cellpadding="0" cellspacing="0" border="0" width="100%" class="wrapper" bgcolor="#F4F4F4">
-        <tr>
-          <td valign="top" bgcolor="#F4F4F4" width="100%">
-            <table width="100%" role="content-container" class="outer" align="center" cellpadding="0" cellspacing="0" border="0">
-              <tr>
-                <td width="100%">
-                  <table width="100%" cellpadding="0" cellspacing="0" border="0">
-                    <tr>
-                      <td>
-                        <!--[if mso]>
-                          <center>
-                          <table><tr><td width="600">
-                          <![endif]-->
-                        <table width="100%" cellpadding="0" cellspacing="0" border="0" style="width: 100%; max-width:600px;" align="center">
-                          <tr>
-                            <td role="modules-container" style="padding: 0px 0px 0px 0px; color: #626262; text-align: left;" bgcolor="#F4F4F4" width="100%"
-                              align="left">
-
-                              <table class="module preheader preheader-hide" role="module" data-type="preheader" border="0" cellpadding="0" cellspacing="0"
-                                width="100%" style="display: none !important; mso-hide: all; visibility: hidden; opacity: 0; color: transparent; height: 0; width: 0;">
-                                <tr>
-                                  <td role="module-content">
-                                    <p>you have a new notification</p>
-                                  </td>
-                                </tr>
-                              </table>
-
-                              <table class="wrapper" role="module" data-type="image" border="0" cellpadding="0" cellspacing="0" width="100%" style="table-layout: fixed;">
-                                <tr>
-                                  <td style="font-size:6px;line-height:10px;padding:20px 0px 20px 0px;" valign="top" align="center">
-                                    <img class="max-width" border="0" style="display:block;color:#000000;text-decoration:none;font-family:Helvetica, arial, sans-serif;font-size:16px;max-width:10% !important;width:10%;height:auto !important;"
-                                      src="https://marketing-image-production.s3.amazonaws.com/uploads/bb39b20cf15e52c1c0933676e25f2b2402737c6560b8098c204ad6932b84eb2058804376dbc4db138c7a21dcaed9325bde36185648afac5bc97e3d73d4e12718.png"
-                                      alt="" width="60">
-                                  </td>
-                                </tr>
-                              </table>
\ No newline at end of file
diff --git a/packages/component-helper-service/src/services/email/templates/simpleCTA.html b/packages/component-helper-service/src/services/email/templates/simpleCTA.html
deleted file mode 100644
index 4d5a97b25445b85f27874470ab76864ccc45b3dd..0000000000000000000000000000000000000000
--- a/packages/component-helper-service/src/services/email/templates/simpleCTA.html
+++ /dev/null
@@ -1,4 +0,0 @@
-{{> header }}
-{{> mainBody }}
-{{> mainButton }}
-{{> footer }}
diff --git a/packages/component-helper-service/src/services/services.js b/packages/component-helper-service/src/services/services.js
index d489c28253937065f6864027bcf2d75b1299c5f1..dab0fae58764405a3b8b4c5add996ee43657fe2b 100644
--- a/packages/component-helper-service/src/services/services.js
+++ b/packages/component-helper-service/src/services/services.js
@@ -81,10 +81,24 @@ const createUrl = (baseUrl, slug, queryParams = null) =>
     ? `${baseUrl}${slug}`
     : `${baseUrl}${slug}?${querystring.encode(queryParams)}`
 
+const getExpectedDate = ({ timestamp = Date.now(), daysExpected = 0 }) => {
+  const date = new Date(timestamp)
+  let expectedDate = date.getDate() + daysExpected
+  date.setDate(expectedDate)
+
+  expectedDate = date.toLocaleDateString('en-US', {
+    day: 'numeric',
+    month: 'long',
+    year: 'numeric',
+  })
+
+  return expectedDate
+}
 module.exports = {
   checkForUndefinedParams,
   validateEmailAndToken,
   handleNotFoundError,
   getBaseUrl,
   createUrl,
+  getExpectedDate,
 }
diff --git a/packages/component-invite/src/routes/collectionsInvitations/delete.js b/packages/component-invite/src/routes/collectionsInvitations/delete.js
index 5a3b04a96b7eb535347df35c392fee704a48681c..5686d03f2ee8df3c62d1e212fea56cc3bc5a46e0 100644
--- a/packages/component-invite/src/routes/collectionsInvitations/delete.js
+++ b/packages/component-invite/src/routes/collectionsInvitations/delete.js
@@ -1,11 +1,11 @@
-// const mailService = require('pubsweet-component-mail-service')
-
 const {
-  services,
   Team,
+  services,
   authsome: authsomeHelper,
 } = require('pubsweet-component-helper-service')
 
+const notifications = require('./emails/notifications')
+
 module.exports = models => async (req, res) => {
   const { collectionId, invitationId } = req.params
   const teamHelper = new Team({ TeamModel: models.Team, collectionId })
@@ -56,10 +56,14 @@ module.exports = models => async (req, res) => {
     user.teams = user.teams.filter(userTeamId => team.id !== userTeamId)
     await user.save()
 
-    // mailService.sendSimpleEmail({
-    //   toEmail: user.email,
-    //   emailType: 'revoke-handling-editor',
-    // })
+    notifications.sendNotifications({
+      models,
+      collection,
+      isEiC: true,
+      invitedHE: user,
+      isCanceled: true,
+      baseUrl: services.getBaseUrl(req),
+    })
 
     return res.status(200).json({})
   } catch (e) {
diff --git a/packages/component-invite/src/routes/collectionsInvitations/emails/emailCopy.js b/packages/component-invite/src/routes/collectionsInvitations/emails/emailCopy.js
new file mode 100644
index 0000000000000000000000000000000000000000..eb8f75cbd4816f8aba6a7a3c6001e7afec19999f
--- /dev/null
+++ b/packages/component-invite/src/routes/collectionsInvitations/emails/emailCopy.js
@@ -0,0 +1,28 @@
+const getEmailCopy = ({ emailType, titleText, targetUserName, comments }) => {
+  let paragraph, hasLink
+  switch (emailType) {
+    case 'he-assigned':
+      paragraph = `You have been assigned as a Handling Editor to ${titleText}. Please click on the link below to access the manuscript and make a decision.`
+      break
+    case 'he-accepted':
+      paragraph = `Dr. ${targetUserName} agreed to be a Handling Editor on ${titleText}. Please click on the link below to access the manuscript.`
+      break
+    case 'he-declined':
+      paragraph = `Dr. ${targetUserName} has declined to be a Handling Editor on ${titleText}.<br/><br/>
+      ${comments}`
+      hasLink = false
+      break
+    case 'he-revoked':
+      paragraph = `Your Handling Editor assignment to ${titleText} has been revoked.`
+      hasLink = false
+      break
+    default:
+      throw new Error(`The ${emailType} email type is not defined.`)
+  }
+
+  return { paragraph, hasLink }
+}
+
+module.exports = {
+  getEmailCopy,
+}
diff --git a/packages/component-invite/src/routes/collectionsInvitations/emails/notifications.js b/packages/component-invite/src/routes/collectionsInvitations/emails/notifications.js
new file mode 100644
index 0000000000000000000000000000000000000000..3b02231bdc3d8e15f6929c1e8da58dea8c84e5fe
--- /dev/null
+++ b/packages/component-invite/src/routes/collectionsInvitations/emails/notifications.js
@@ -0,0 +1,144 @@
+const config = require('config')
+const { last } = require('lodash')
+
+const unsubscribeSlug = config.get('unsubscribe.url')
+
+const {
+  User,
+  Email,
+  services,
+  Fragment,
+} = require('pubsweet-component-helper-service')
+
+const { getEmailCopy } = require('./emailCopy')
+
+module.exports = {
+  async sendNotifications({
+    reason,
+    baseUrl,
+    invitedHE,
+    collection,
+    isEiC = false,
+    isCanceled = false,
+    isAccepted = false,
+    models: { User: UserModel, Fragment: FragmentModel },
+  }) {
+    const fragmentId = last(collection.fragments)
+    const fragment = await FragmentModel.find(fragmentId)
+    const fragmentHelper = new Fragment({ fragment })
+    const { title } = await fragmentHelper.getFragmentData()
+    const { submittingAuthor } = await fragmentHelper.getAuthorData({
+      UserModel,
+    })
+
+    const titleText = `the manuscript titled "${title}" by ${
+      submittingAuthor.firstName
+    } ${submittingAuthor.firstName}`
+
+    const userHelper = new User({ UserModel })
+    const eic = await userHelper.getEditorInChief()
+    const eicName = `${eic.firstName} ${eic.lastName}`
+    const subjectBaseText = `${collection.customId}: Manuscript `
+
+    const email = new Email({
+      type: 'user',
+      content: {
+        signatureName: eicName,
+        ctaLink: services.createUrl(
+          baseUrl,
+          `/projects/${collection.id}/versions/${fragment.id}/details`,
+        ),
+        ctaText: 'MANUSCRIPT DETAILS',
+      },
+    })
+
+    if (isEiC) {
+      sendInvitedHEEmail({
+        email,
+        baseUrl,
+        eicName,
+        isCanceled,
+        titleText,
+        subjectBaseText,
+        handlingEditor: invitedHE,
+      })
+    } else {
+      sendEiCEmail({
+        eic,
+        email,
+        baseUrl,
+        comments: reason ? `Reason: "${reason}"` : '',
+        titleText,
+        isAccepted,
+        subjectBaseText,
+        targetUserName: `${invitedHE.firstName} ${invitedHE.lastName}`,
+      })
+    }
+  },
+}
+
+const sendInvitedHEEmail = ({
+  email,
+  eicName,
+  baseUrl,
+  titleText,
+  isCanceled,
+  handlingEditor,
+  subjectBaseText,
+}) => {
+  email.toUser = {
+    email: handlingEditor.email,
+    name: handlingEditor.name,
+  }
+
+  email.content.subject = isCanceled
+    ? `${subjectBaseText} Assignment Revoked`
+    : `${subjectBaseText} Assignment`
+  email.content.unsubscribeLink = services.createUrl(baseUrl, unsubscribeSlug, {
+    id: handlingEditor.id,
+  })
+  email.content.signatureName = eicName
+
+  const { html, text } = email.getBody({
+    body: getEmailCopy({
+      emailType: isCanceled ? 'he-revoked' : 'he-assigned',
+      titleText,
+    }),
+  })
+
+  email.sendEmail({ html, text })
+}
+
+const sendEiCEmail = async ({
+  eic,
+  email,
+  baseUrl,
+  comments,
+  titleText,
+  isAccepted,
+  targetUserName,
+  subjectBaseText,
+}) => {
+  email.content.subject = `${subjectBaseText} Assignment Response`
+  const emailType = isAccepted ? 'he-accepted' : 'he-declined'
+
+  email.toUser = {
+    email: eic.email,
+    name: `${eic.firstName} ${eic.lastName}`,
+  }
+
+  email.content.unsubscribeLink = services.createUrl(baseUrl, unsubscribeSlug, {
+    id: eic.id,
+  })
+
+  const { html, text } = email.getBody({
+    body: getEmailCopy({
+      comments,
+      emailType,
+      titleText,
+      targetUserName,
+    }),
+  })
+
+  email.sendEmail({ html, text })
+}
diff --git a/packages/component-invite/src/routes/collectionsInvitations/patch.js b/packages/component-invite/src/routes/collectionsInvitations/patch.js
index caa61f182b13113527c81c495e3d08e70b66dea8..28452a347b73af471b0ff6eaaa8bbffc8e259df9 100644
--- a/packages/component-invite/src/routes/collectionsInvitations/patch.js
+++ b/packages/component-invite/src/routes/collectionsInvitations/patch.js
@@ -1,12 +1,10 @@
-// const mailService = require('pubsweet-component-mail-service')
-
 const {
   Team,
-  // User,
   services,
   Collection,
   Invitation,
 } = require('pubsweet-component-helper-service')
+const notifications = require('./emails/notifications')
 
 module.exports = models => async (req, res) => {
   const { collectionId, invitationId } = req.params
@@ -35,53 +33,34 @@ module.exports = models => async (req, res) => {
       })
 
     const collectionHelper = new Collection({ collection })
-    // const baseUrl = services.getBaseUrl(req)
 
     const teamHelper = new Team({ TeamModel: models.Team, collectionId })
-    // const userHelper = new User({ UserModel })
 
     await collectionHelper.updateHandlingEditor({ isAccepted })
     invitation.respondedOn = Date.now()
     invitation.hasAnswer = true
-    // const eic = await userHelper.getEditorInChief()
-    // const toEmail = eic.email
-
-    if (isAccepted) {
-      invitation.isAccepted = true
-      await collection.save()
+    invitation.isAccepted = isAccepted
 
-      // mailService.sendSimpleEmail({
-      //   toEmail,
-      //   user,
-      //   emailType: 'handling-editor-agreed',
-      //   dashboardUrl: baseUrl,
-      //   meta: {
-      //     collectionId: collection.customId,
-      //   },
-      // })
+    if (!isAccepted) {
+      await teamHelper.deleteHandlingEditor({
+        collection,
+        role: invitation.role,
+        user,
+      })
 
-      return res.status(200).json(invitation)
+      if (reason) invitation.reason = reason
     }
 
-    await teamHelper.deleteHandlingEditor({
-      collection,
-      role: invitation.role,
-      user,
-    })
-
-    invitation.isAccepted = false
-    if (reason) invitation.reason = reason
     await collection.save()
 
-    // mailService.sendSimpleEmail({
-    //   toEmail,
-    //   user,
-    //   emailType: 'handling-editor-declined',
-    //   meta: {
-    //     reason,
-    //     collectionId: collection.customId,
-    //   },
-    // })
+    notifications.sendNotifications({
+      models,
+      reason,
+      collection,
+      isAccepted,
+      invitedHE: user,
+      baseUrl: services.getBaseUrl(req),
+    })
 
     return res.status(200).json(invitation)
   } catch (e) {
diff --git a/packages/component-invite/src/routes/collectionsInvitations/post.js b/packages/component-invite/src/routes/collectionsInvitations/post.js
index 93be34ea5cd3b0896b6ed332898c6736bbf58437..d1c3eae146fcb68eb139b8d5d4374b016ebdfa80 100644
--- a/packages/component-invite/src/routes/collectionsInvitations/post.js
+++ b/packages/component-invite/src/routes/collectionsInvitations/post.js
@@ -1,13 +1,15 @@
 const logger = require('@pubsweet/logger')
-// const mailService = require('pubsweet-component-mail-service')
+
 const {
+  Team,
   services,
-  authsome: authsomeHelper,
   Collection,
-  Team,
   Invitation,
+  authsome: authsomeHelper,
 } = require('pubsweet-component-helper-service')
 
+const notifications = require('./emails/notifications')
+
 module.exports = models => async (req, res) => {
   const { email, role } = req.body
 
@@ -50,7 +52,6 @@ module.exports = models => async (req, res) => {
     })
 
   const collectionHelper = new Collection({ collection })
-  // const baseUrl = services.getBaseUrl(req)
 
   const teamHelper = new Team({
     TeamModel: models.Team,
@@ -83,12 +84,13 @@ module.exports = models => async (req, res) => {
     await collection.save()
     await collectionHelper.addHandlingEditor({ user, invitation })
 
-    // mailService.sendSimpleEmail({
-    //   toEmail: user.email,
-    //   user,
-    //   emailType: 'assign-handling-editor',
-    //   dashboardUrl: baseUrl,
-    // })
+    notifications.sendNotifications({
+      models,
+      collection,
+      isEiC: true,
+      invitedHE: user,
+      baseUrl: services.getBaseUrl(req),
+    })
 
     return res.status(200).json(invitation)
   } catch (e) {
diff --git a/packages/component-invite/src/routes/fragmentsInvitations/decline.js b/packages/component-invite/src/routes/fragmentsInvitations/decline.js
index eff9fb09c5feaba97fa5f516f9e53364aae88212..ce05ea782bd0ea54f4b50a4ba0921aa5ea9fc795 100644
--- a/packages/component-invite/src/routes/fragmentsInvitations/decline.js
+++ b/packages/component-invite/src/routes/fragmentsInvitations/decline.js
@@ -1,11 +1,11 @@
 const {
-  Email,
   services,
-  Fragment,
   Invitation,
   authsome: authsomeHelper,
 } = require('pubsweet-component-helper-service')
 
+const notifications = require('./emails/notifications')
+
 module.exports = models => async (req, res) => {
   const { collectionId, invitationId, fragmentId } = req.params
   const { invitationToken } = req.body
@@ -54,27 +54,16 @@ module.exports = models => async (req, res) => {
     invitation.isAccepted = false
     await fragment.save()
 
-    const fragmentHelper = new Fragment({ fragment })
-    const parsedFragment = await fragmentHelper.getFragmentData({
-      handlingEditor: collection.handlingEditor,
-    })
     const baseUrl = services.getBaseUrl(req)
-    const {
-      authorsList: authors,
-      submittingAuthor,
-    } = await fragmentHelper.getAuthorData({ UserModel })
-    const emailHelper = new Email({
-      UserModel,
-      collection,
-      parsedFragment,
+
+    notifications.sendNotifications({
       baseUrl,
-      authors,
-    })
-    emailHelper.setupReviewerDecisionEmail({
-      authorName: `${submittingAuthor.firstName} ${submittingAuthor.lastName}`,
-      agree: false,
-      user,
+      fragment,
+      collection,
+      UserModel: models.User,
+      reviewer: user,
     })
+
     return res.status(200).json({})
   } catch (e) {
     const notFoundError = await services.handleNotFoundError(e, 'item')
diff --git a/packages/component-invite/src/routes/fragmentsInvitations/delete.js b/packages/component-invite/src/routes/fragmentsInvitations/delete.js
index af74f13d32a60e8cac0c18837b23c57b384d2570..cd72deeb2b0134a965f1eed55b818bd132f8ce15 100644
--- a/packages/component-invite/src/routes/fragmentsInvitations/delete.js
+++ b/packages/component-invite/src/routes/fragmentsInvitations/delete.js
@@ -1,12 +1,12 @@
 const {
-  services,
   Team,
-  Email,
-  Fragment,
+  services,
   Collection,
   authsome: authsomeHelper,
 } = require('pubsweet-component-helper-service')
 
+const notifications = require('./emails/notifications')
+
 module.exports = models => async (req, res) => {
   const { collectionId, invitationId, fragmentId } = req.params
   const teamHelper = new Team({
@@ -67,26 +67,16 @@ module.exports = models => async (req, res) => {
     user.teams = user.teams.filter(userTeamId => team.id !== userTeamId)
     await user.save()
 
-    const fragmentHelper = new Fragment({ fragment })
-    const parsedFragment = await fragmentHelper.getFragmentData({
-      handlingEditor: collection.handlingEditor,
-    })
     const baseUrl = services.getBaseUrl(req)
-    const {
-      authorsList: authors,
-      submittingAuthor,
-    } = await fragmentHelper.getAuthorData({ UserModel })
-    const emailHelper = new Email({
-      UserModel,
-      collection,
-      parsedFragment,
-      baseUrl,
-      authors,
-    })
 
-    emailHelper.setupReviewerUnassignEmail({
-      user,
-      authorName: `${submittingAuthor.firstName} ${submittingAuthor.lastName}`,
+    notifications.sendNotifications({
+      baseUrl,
+      fragment,
+      collection,
+      isHE: true,
+      reviewer: user,
+      isCanceled: true,
+      UserModel: models.User,
     })
 
     return res.status(200).json({})
diff --git a/packages/component-invite/src/routes/fragmentsInvitations/emails/emailCopy.js b/packages/component-invite/src/routes/fragmentsInvitations/emails/emailCopy.js
new file mode 100644
index 0000000000000000000000000000000000000000..7f7f868597d14f5dd808e31cb6fc51b30fe9c00d
--- /dev/null
+++ b/packages/component-invite/src/routes/fragmentsInvitations/emails/emailCopy.js
@@ -0,0 +1,58 @@
+const config = require('config')
+
+const getEmailCopy = ({
+  emailType,
+  titleText,
+  expectedDate,
+  targetUserName,
+}) => {
+  let upperContent, manuscriptText, lowerContent, paragraph, hasLink
+  switch (emailType) {
+    case 'reviewer-invitation':
+      upperContent = `${titleText}, has been submitted for possible publication in Hindawi. As the Academic Editor handling the manuscript, I would be delighted if you would agree to review it and let me know whether you feel it is suitable for publication.`
+      manuscriptText =
+        "The manuscript's abstract, and author information is below to help you decide. Once you have agreed to review, you will be able to download the full article PDF."
+      lowerContent = `If a potential conflict of interest exists between yourself and either the authors or
+      the subject of the manuscript, please decline to handle the manuscript. If a conflict
+      becomes apparent during the review process, please let me know at the earliest possible
+      opportunity. For more information about our conflicts of interest policies, please
+      see:
+      <a href="https://www.hindawi.com/ethics/#coi">https://www.hindawi.com/ethics/#coi</a>.
+      If you are able to review the manuscript, I would be grateful if you could submit your
+      report by ${expectedDate}.`
+      break
+    case 'reviewer-resend-invitation':
+      upperContent = `On ${expectedDate} I sent you a request to review ${titleText}, submitted for possible publication in Hindawi.
+        I would be grateful if you would agree to review it and let me know whether you feel
+        it is suitable for publication. If you are unable to review this manuscript then
+        please decline to review. More details are available by clicking the link.`
+      lowerContent =
+        'I would like to thank you in advance for your help with the evaluation of this manuscript, since it would not be possible for us to run the journal without the help of our reviewers. I am looking forward to hearing from you.'
+      break
+    case 'reviewer-accepted':
+      paragraph = `We are pleased to inform you that Dr. ${targetUserName} has agreed to review ${titleText}. You should receive the report by Dr. ${targetUserName} before ${expectedDate}. If you have any queries, or would like to send a reminder if you no report has been submitted, then please visit the manuscript details page to see the full review.`
+      break
+    case 'reviewer-declined':
+      paragraph = `We regret to inform you that Dr. ${targetUserName} has declined to review ${titleText}. Please visit the manuscript details page to see if you need to invite any additional reviewers in order to reach a decision on the manuscript`
+      break
+    case 'reviewer-thank-you':
+      paragraph = `Thank you for agreeing to review ${titleText}. You can view the full PDF file of the manuscript and post your review report using the following URL:`
+      break
+    case 'reviewer-cancel-invitation':
+      paragraph = `You are no longer needed to review ${titleText}. If you have comments on this manuscript you believe the Editor should
+        see, please email them to ${config.get(
+          'mailer.from',
+        )} as soon as possible. Thank you for your
+        time and I hope you will consider reviewing for Hindawi again.`
+      hasLink = false
+      break
+    default:
+      throw new Error(`The ${emailType} email type is not defined.`)
+  }
+
+  return { upperContent, manuscriptText, lowerContent, paragraph, hasLink }
+}
+
+module.exports = {
+  getEmailCopy,
+}
diff --git a/packages/component-invite/src/routes/fragmentsInvitations/emails/invitations.js b/packages/component-invite/src/routes/fragmentsInvitations/emails/invitations.js
new file mode 100644
index 0000000000000000000000000000000000000000..fb2ab742c4d69892ee55d37f5a42fd60ad91957a
--- /dev/null
+++ b/packages/component-invite/src/routes/fragmentsInvitations/emails/invitations.js
@@ -0,0 +1,136 @@
+const config = require('config')
+const { get } = require('lodash')
+
+const unsubscribeSlug = config.get('unsubscribe.url')
+const resetPasswordPath = config.get('invite-reviewer.url')
+
+const {
+  Email,
+  services,
+  Fragment,
+} = require('pubsweet-component-helper-service')
+
+const { getEmailCopy } = require('./emailCopy')
+
+module.exports = {
+  async sendInvitations({
+    resend,
+    baseUrl,
+    fragment,
+    UserModel,
+    timestamp,
+    collection,
+    invitation,
+    invitedUser,
+  }) {
+    const fragmentHelper = new Fragment({ fragment })
+    const { title, abstract } = await fragmentHelper.getFragmentData({
+      handlingEditor: collection.handlingEditor,
+    })
+    const {
+      activeAuthors: authors,
+      submittingAuthor,
+    } = await fragmentHelper.getAuthorData({
+      UserModel,
+    })
+
+    const subjectBaseText = `${collection.customId}: Review`
+    const titleText = `The manuscript titled "${title}" by ${
+      submittingAuthor.firstName
+    } ${submittingAuthor.firstName}`
+
+    let queryParams = {
+      invitationId: invitation.id,
+      agree: true,
+    }
+
+    const detailsPath = `/projects/${collection.id}/versions/${
+      fragment.id
+    }/details`
+
+    const declineLink = services.createUrl(baseUrl, resetPasswordPath, {
+      ...queryParams,
+      agree: false,
+      fragmentId: fragment.id,
+      collectionId: collection.id,
+      invitationToken: invitedUser.invitationToken,
+    })
+
+    let agreeLink = services.createUrl(baseUrl, detailsPath, queryParams)
+
+    if (!invitedUser.isConfirmed) {
+      queryParams = {
+        ...queryParams,
+        email: invitedUser.email,
+        token: invitedUser.passwordResetToken,
+        collectionId: collection.id,
+        fragmentId: fragment.id,
+        agree: true,
+      }
+      agreeLink = services.createUrl(baseUrl, resetPasswordPath, queryParams)
+    }
+
+    const email = new Email({
+      type: 'user',
+      toUser: {
+        email: invitedUser.email,
+        name: `${invitedUser.firstName} ${invitedUser.lastName}`,
+      },
+      content: {
+        authors,
+        abstract,
+        agreeLink,
+        declineLink,
+        subject: `${subjectBaseText} Requested`,
+        detailsLink: services.createUrl(baseUrl, detailsPath),
+        signatureName: get(collection, 'handlingEditor.name', 'Hindawi'),
+        unsubscribeLink: services.createUrl(baseUrl, unsubscribeSlug, {
+          id: invitedUser.id,
+        }),
+      },
+    })
+
+    sendInvitedUserEmail({
+      email,
+      titleText,
+      resend,
+      timestamp,
+    })
+  },
+}
+
+const sendInvitedUserEmail = async ({
+  email,
+  titleText,
+  resend,
+  timestamp,
+}) => {
+  const emailType =
+    resend === true ? 'reviewer-resend-invitation ' : 'reviewer-invitation'
+  const daysExpected = resend === true ? 0 : 14
+
+  const { html, text } = email.getBody({
+    isReviewerInvitation: true,
+    body: getEmailCopy({
+      emailType,
+      titleText,
+      expectedDate: getExpectedDate({ timestamp, daysExpected }),
+    }),
+  })
+
+  email.sendEmail({ html, text })
+}
+
+const getExpectedDate = ({ timestamp = Date.now(), daysExpected = 0 }) => {
+  const date = new Date(timestamp)
+  let expectedDate = date.getDate() + daysExpected
+  date.setDate(expectedDate)
+
+  expectedDate = date.toLocaleDateString('en-US', {
+    day: 'numeric',
+    month: 'long',
+    year: 'numeric',
+  })
+
+  return expectedDate
+}
diff --git a/packages/component-invite/src/routes/fragmentsInvitations/emails/notifications.js b/packages/component-invite/src/routes/fragmentsInvitations/emails/notifications.js
new file mode 100644
index 0000000000000000000000000000000000000000..34b6e6f51c517e013b09229e8675a64f65b38380
--- /dev/null
+++ b/packages/component-invite/src/routes/fragmentsInvitations/emails/notifications.js
@@ -0,0 +1,148 @@
+const config = require('config')
+const { get } = require('lodash')
+
+const unsubscribeSlug = config.get('unsubscribe.url')
+
+const {
+  User,
+  Email,
+  services,
+  Fragment,
+} = require('pubsweet-component-helper-service')
+
+const { getEmailCopy } = require('./emailCopy')
+
+module.exports = {
+  async sendNotifications({
+    baseUrl,
+    fragment,
+    reviewer,
+    UserModel,
+    collection,
+    isHE = false,
+    isAccepted = false,
+    isCanceled = false,
+  }) {
+    const fragmentHelper = new Fragment({ fragment })
+    const { title } = await fragmentHelper.getFragmentData({
+      handlingEditor: collection.handlingEditor,
+    })
+    const { submittingAuthor } = await fragmentHelper.getAuthorData({
+      UserModel,
+    })
+
+    const titleText = `the manuscript titled "${title}" by ${
+      submittingAuthor.firstName
+    } ${submittingAuthor.firstName}`
+
+    const handlingEditor = get(collection, 'handlingEditor')
+    const userHelper = new User({ UserModel })
+    const { firstName, lastName } = await userHelper.getEditorInChief()
+    const eicName = `${firstName} ${lastName}`
+    const subjectBaseText = isCanceled
+      ? `${collection.customId}: Reviewer `
+      : `${collection.customId}: Manuscript `
+
+    const email = new Email({
+      type: 'user',
+      content: {
+        signatureName: handlingEditor.name,
+        ctaLink: services.createUrl(
+          baseUrl,
+          `/projects/${collection.id}/versions/${fragment.id}/details`,
+        ),
+        ctaText: 'MANUSCRIPT DETAILS',
+      },
+    })
+
+    if (isHE) {
+      sendReviewerEmail({
+        email,
+        baseUrl,
+        reviewer,
+        titleText,
+        isCanceled,
+        subjectBaseText,
+      })
+    } else {
+      sendHandlingEditorEmail({
+        email,
+        eicName,
+        titleText,
+        handlingEditor,
+        targetUserName: `${reviewer.firstName} ${reviewer.lastName}`,
+        emailType:
+          isAccepted === true ? 'reviewer-accepted' : 'reviewer-declined',
+      })
+    }
+  },
+}
+
+const sendHandlingEditorEmail = ({
+  email,
+  eicName,
+  baseUrl,
+  titleText,
+  emailType,
+  handlingEditor,
+  targetUserName,
+  subjectBaseText,
+}) => {
+  email.toUser = {
+    email: handlingEditor.email,
+    name: handlingEditor.name,
+  }
+
+  email.content.subject = `${subjectBaseText} Reviews`
+  email.content.unsubscribeLink = services.createUrl(baseUrl, unsubscribeSlug, {
+    id: handlingEditor.id,
+  })
+  email.content.signatureName = eicName
+
+  const { html, text } = email.getBody({
+    body: getEmailCopy({
+      emailType,
+      titleText,
+      expectedDate: services.getExpectedDate({
+        timestamp: Date.now(),
+        daysExpected: 14,
+      }),
+      targetUserName,
+    }),
+  })
+  email.sendEmail({ html, text })
+}
+
+const sendReviewerEmail = async ({
+  email,
+  baseUrl,
+  reviewer,
+  titleText,
+  isCanceled,
+  subjectBaseText,
+}) => {
+  email.content.subject = isCanceled
+    ? `${subjectBaseText} Unassigned`
+    : `${subjectBaseText} Review`
+  const emailType = isCanceled
+    ? 'reviewer-cancel-invitation'
+    : 'reviewer-thank-you'
+
+  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: getEmailCopy({
+      emailType,
+      titleText,
+    }),
+  })
+
+  email.sendEmail({ html, text })
+}
diff --git a/packages/component-invite/src/routes/fragmentsInvitations/patch.js b/packages/component-invite/src/routes/fragmentsInvitations/patch.js
index 15c8359e94ff8a3c359252d70000050e5e43ed70..f9f7bc9ce43a011f809310a9a4bc9d7903fc2425 100644
--- a/packages/component-invite/src/routes/fragmentsInvitations/patch.js
+++ b/packages/component-invite/src/routes/fragmentsInvitations/patch.js
@@ -1,12 +1,12 @@
 const {
-  Email,
   services,
-  Fragment,
   Collection,
   Invitation,
   authsome: authsomeHelper,
 } = require('pubsweet-component-helper-service')
 
+const notifications = require('./emails/notifications')
+
 module.exports = models => async (req, res) => {
   const { collectionId, invitationId, fragmentId } = req.params
   const { isAccepted, reason } = req.body
@@ -20,7 +20,9 @@ module.exports = models => async (req, res) => {
       return res.status(400).json({
         error: `Fragment ${fragmentId} does not match collection ${collectionId}`,
       })
+
     const fragment = await models.Fragment.find(fragmentId)
+
     fragment.invitations = fragment.invitations || []
     const invitation = await fragment.invitations.find(
       invitation => invitation.id === invitationId,
@@ -31,6 +33,7 @@ module.exports = models => async (req, res) => {
       role: 'reviewer',
       invitation,
     })
+
     const invitationValidation = invitationHelper.validateInvitation()
     if (invitationValidation.error)
       return res.status(invitationValidation.status).json({
@@ -45,54 +48,32 @@ module.exports = models => async (req, res) => {
       })
 
     const collectionHelper = new Collection({ collection })
-    const fragmentHelper = new Fragment({ fragment })
-    const parsedFragment = await fragmentHelper.getFragmentData({
-      handlingEditor: collection.handlingEditor,
-    })
     const baseUrl = services.getBaseUrl(req)
-    const {
-      authorsList: authors,
-      submittingAuthor,
-    } = await fragmentHelper.getAuthorData({ UserModel })
-    const emailHelper = new Email({
-      UserModel,
-      collection,
-      parsedFragment,
-      baseUrl,
-      authors,
-    })
 
     invitation.respondedOn = Date.now()
     invitation.hasAnswer = true
+    invitation.isAccepted = isAccepted
+
     if (isAccepted) {
-      invitation.isAccepted = true
-      if (collection.status === 'reviewersInvited')
-        await collectionHelper.updateStatus({ newStatus: 'underReview' })
+      if (collection.status === 'reviewersInvited') {
+        collectionHelper.updateStatus({ newStatus: 'underReview' })
+      }
+      fragment.save()
+    } else {
+      if (reason) invitation.reason = reason
       await fragment.save()
-
-      emailHelper.setupReviewerDecisionEmail({
-        agree: true,
-        timestamp: invitation.respondedOn,
-        user,
-        authorName: `${submittingAuthor.firstName} ${
-          submittingAuthor.lastName
-        }`,
+      collectionHelper.updateStatusByNumberOfReviewers({
+        invitations: fragment.invitations,
       })
-
-      return res.status(200).json(invitation)
     }
 
-    invitation.isAccepted = false
-    if (reason) invitation.reason = reason
-    await fragment.save()
-
-    collectionHelper.updateStatusByNumberOfReviewers({
-      invitations: fragment.invitations,
-    })
-
-    emailHelper.setupReviewerDecisionEmail({
-      agree: false,
-      user,
+    notifications.sendNotifications({
+      baseUrl,
+      fragment,
+      isAccepted,
+      collection,
+      reviewer: user,
+      UserModel: models.User,
     })
 
     return res.status(200).json(invitation)
diff --git a/packages/component-invite/src/routes/fragmentsInvitations/post.js b/packages/component-invite/src/routes/fragmentsInvitations/post.js
index e6bab24045d9a4d10252cde11f6fb3da2d1daae5..29b0224645840d139c69801eefb3470abb26dd3a 100644
--- a/packages/component-invite/src/routes/fragmentsInvitations/post.js
+++ b/packages/component-invite/src/routes/fragmentsInvitations/post.js
@@ -1,15 +1,15 @@
 const logger = require('@pubsweet/logger')
 const {
-  Email,
+  Team,
+  User,
   services,
-  authsome: authsomeHelper,
-  Fragment,
   Collection,
-  Team,
   Invitation,
-  User,
+  authsome: authsomeHelper,
 } = require('pubsweet-component-helper-service')
 
+const emailInvitations = require('./emails/invitations')
+
 module.exports = models => async (req, res) => {
   const { email, role } = req.body
 
@@ -59,23 +59,9 @@ module.exports = models => async (req, res) => {
     })
 
   const collectionHelper = new Collection({ collection })
-  const fragmentHelper = new Fragment({ fragment })
-  const handlingEditor = collection.handlingEditor || {}
-  const parsedFragment = await fragmentHelper.getFragmentData({
-    handlingEditor,
-  })
+
   const baseUrl = services.getBaseUrl(req)
-  const {
-    authorsList: authors,
-    submittingAuthor,
-  } = await fragmentHelper.getAuthorData({ UserModel })
-  const emailHelper = new Email({
-    UserModel,
-    collection,
-    parsedFragment,
-    baseUrl,
-    authors,
-  })
+
   const teamHelper = new Team({
     TeamModel: models.Team,
     collectionId,
@@ -102,10 +88,11 @@ module.exports = models => async (req, res) => {
     let resend = false
 
     if (invitation) {
-      if (invitation.hasAnswer)
+      if (invitation.hasAnswer) {
         return res
           .status(400)
           .json({ error: 'User has already replied to a previous invitation.' })
+      }
 
       invitation.invitedOn = Date.now()
       await fragment.save()
@@ -116,15 +103,19 @@ module.exports = models => async (req, res) => {
       })
     }
 
-    if (collection.status === 'heAssigned')
-      await collectionHelper.updateStatus({ newStatus: 'reviewersInvited' })
+    if (collection.status === 'heAssigned') {
+      collectionHelper.updateStatus({ newStatus: 'reviewersInvited' })
+    }
 
-    emailHelper.setupReviewerInvitationEmail({
-      user,
-      invitationId: invitation.id,
-      timestamp: invitation.invitedOn,
+    emailInvitations.sendInvitations({
       resend,
-      authorName: `${submittingAuthor.firstName} ${submittingAuthor.lastName}`,
+      baseUrl,
+      fragment,
+      collection,
+      invitation,
+      invitedUser: user,
+      UserModel: models.User,
+      timestamp: invitation.invitedOn,
     })
 
     return res.status(200).json(invitation)
@@ -155,11 +146,14 @@ module.exports = models => async (req, res) => {
       parentObject: fragment,
     })
 
-    emailHelper.setupReviewerInvitationEmail({
-      user: newUser,
-      invitationId: invitation.id,
+    emailInvitations.sendInvitations({
+      baseUrl,
+      fragment,
+      collection,
+      invitation,
+      invitedUser: newUser,
+      UserModel: models.User,
       timestamp: invitation.invitedOn,
-      authorName: `${submittingAuthor.firstName} ${submittingAuthor.lastName}`,
     })
 
     return res.status(200).json(invitation)
diff --git a/packages/component-invite/src/tests/collectionsInvitations/delete.test.js b/packages/component-invite/src/tests/collectionsInvitations/delete.test.js
index 7fdef707ccadb721ce6099a69001da73ec29c552..c6e6089b02c4946f6a624911036cf2736a905d77 100644
--- a/packages/component-invite/src/tests/collectionsInvitations/delete.test.js
+++ b/packages/component-invite/src/tests/collectionsInvitations/delete.test.js
@@ -6,8 +6,8 @@ const fixturesService = require('pubsweet-component-fixture-service')
 const requests = require('../requests')
 
 const { Model, fixtures } = fixturesService
-jest.mock('pubsweet-component-mail-service', () => ({
-  sendSimpleEmail: jest.fn(),
+jest.mock('@pubsweet/component-send-email', () => ({
+  send: jest.fn(),
 }))
 
 const path = '../routes/collectionsInvitations/delete'
diff --git a/packages/component-invite/src/tests/collectionsInvitations/patch.test.js b/packages/component-invite/src/tests/collectionsInvitations/patch.test.js
index 11c7b1ded658ae9a41fabddd636d7a48f6d2560b..3bc33a435bdfe9cdb530614955e8146929218b2a 100644
--- a/packages/component-invite/src/tests/collectionsInvitations/patch.test.js
+++ b/packages/component-invite/src/tests/collectionsInvitations/patch.test.js
@@ -6,10 +6,8 @@ const cloneDeep = require('lodash/cloneDeep')
 const fixturesService = require('pubsweet-component-fixture-service')
 
 const { Model, fixtures } = fixturesService
-jest.mock('pubsweet-component-mail-service', () => ({
-  sendSimpleEmail: jest.fn(),
-  sendNotificationEmail: jest.fn(),
-  sendReviewerInvitationEmail: jest.fn(),
+jest.mock('@pubsweet/component-send-email', () => ({
+  send: jest.fn(),
 }))
 
 const reqBody = {
diff --git a/packages/component-invite/src/tests/collectionsInvitations/post.test.js b/packages/component-invite/src/tests/collectionsInvitations/post.test.js
index 0608aced450fbf604c14fb2af509309262808ddc..18e7ce2b1944aa5f6c33fbe0ae9fb60e56ee791b 100644
--- a/packages/component-invite/src/tests/collectionsInvitations/post.test.js
+++ b/packages/component-invite/src/tests/collectionsInvitations/post.test.js
@@ -8,11 +8,10 @@ const requests = require('../requests')
 
 const { Model, fixtures } = fixturesService
 
-jest.mock('pubsweet-component-mail-service', () => ({
-  sendSimpleEmail: jest.fn(),
-  sendNotificationEmail: jest.fn(),
-  sendReviewerInvitationEmail: jest.fn(),
+jest.mock('@pubsweet/component-send-email', () => ({
+  send: jest.fn(),
 }))
+
 const chance = new Chance()
 const reqBody = {
   email: chance.email(),
diff --git a/packages/component-invite/src/tests/fragmentsInvitations/decline.test.js b/packages/component-invite/src/tests/fragmentsInvitations/decline.test.js
index 5365092f9902a39574356886fdcb448f5404e767..0357e6c500ccc2a865352b93715dd8ea6fed7c83 100644
--- a/packages/component-invite/src/tests/fragmentsInvitations/decline.test.js
+++ b/packages/component-invite/src/tests/fragmentsInvitations/decline.test.js
@@ -7,8 +7,8 @@ const fixturesService = require('pubsweet-component-fixture-service')
 const { Model, fixtures } = fixturesService
 const cloneDeep = require('lodash/cloneDeep')
 
-jest.mock('pubsweet-component-mail-service', () => ({
-  sendNotificationEmail: jest.fn(),
+jest.mock('@pubsweet/component-send-email', () => ({
+  send: jest.fn(),
 }))
 
 const reqBody = {
diff --git a/packages/component-invite/src/tests/fragmentsInvitations/delete.test.js b/packages/component-invite/src/tests/fragmentsInvitations/delete.test.js
index e19c54ffa1e569dd2b13d579d04ac2ddce3ed099..d7ee683a82165b31adf4b13eb53779be1c1d8b9c 100644
--- a/packages/component-invite/src/tests/fragmentsInvitations/delete.test.js
+++ b/packages/component-invite/src/tests/fragmentsInvitations/delete.test.js
@@ -6,9 +6,8 @@ const fixturesService = require('pubsweet-component-fixture-service')
 const requests = require('../requests')
 
 const { Model, fixtures } = fixturesService
-jest.mock('pubsweet-component-mail-service', () => ({
-  sendSimpleEmail: jest.fn(),
-  sendNotificationEmail: jest.fn(),
+jest.mock('@pubsweet/component-send-email', () => ({
+  send: jest.fn(),
 }))
 
 const path = '../routes/fragmentsInvitations/delete'
diff --git a/packages/component-invite/src/tests/fragmentsInvitations/get.test.js b/packages/component-invite/src/tests/fragmentsInvitations/get.test.js
index b6d6ac08293b0bd359f8ddb08c11ae0a91dcdd03..d30877398cfcf319effc69b265f9f7a7025c295e 100644
--- a/packages/component-invite/src/tests/fragmentsInvitations/get.test.js
+++ b/packages/component-invite/src/tests/fragmentsInvitations/get.test.js
@@ -6,11 +6,10 @@ const fixturesService = require('pubsweet-component-fixture-service')
 const requests = require('../requests')
 
 const { Model, fixtures } = fixturesService
-jest.mock('pubsweet-component-mail-service', () => ({
-  sendSimpleEmail: jest.fn(),
-  sendNotificationEmail: jest.fn(),
-  sendReviewerInvitationEmail: jest.fn(),
+jest.mock('@pubsweet/component-send-email', () => ({
+  send: jest.fn(),
 }))
+
 const path = '../routes/fragmentsInvitations/get'
 const route = {
   path:
diff --git a/packages/component-invite/src/tests/fragmentsInvitations/patch.test.js b/packages/component-invite/src/tests/fragmentsInvitations/patch.test.js
index ce759e90a9e732a2b2c01de245284753a2665a56..8ce62849aeaf74fe31749028fa9cccf1834e6fff 100644
--- a/packages/component-invite/src/tests/fragmentsInvitations/patch.test.js
+++ b/packages/component-invite/src/tests/fragmentsInvitations/patch.test.js
@@ -6,10 +6,8 @@ const cloneDeep = require('lodash/cloneDeep')
 const fixturesService = require('pubsweet-component-fixture-service')
 
 const { Model, fixtures } = fixturesService
-jest.mock('pubsweet-component-mail-service', () => ({
-  sendSimpleEmail: jest.fn(),
-  sendNotificationEmail: jest.fn(),
-  sendReviewerInvitationEmail: jest.fn(),
+jest.mock('@pubsweet/component-send-email', () => ({
+  send: jest.fn(),
 }))
 
 const reqBody = {
diff --git a/packages/component-invite/src/tests/fragmentsInvitations/post.test.js b/packages/component-invite/src/tests/fragmentsInvitations/post.test.js
index c8e76803c5c5b44bf3de1a3e25d5fb118c49ed7b..ce8719050cf2d722720964548e817c814bf2db55 100644
--- a/packages/component-invite/src/tests/fragmentsInvitations/post.test.js
+++ b/packages/component-invite/src/tests/fragmentsInvitations/post.test.js
@@ -8,11 +8,10 @@ const requests = require('../requests')
 
 const { Model, fixtures } = fixturesService
 
-jest.mock('pubsweet-component-mail-service', () => ({
-  sendSimpleEmail: jest.fn(),
-  sendNotificationEmail: jest.fn(),
-  sendReviewerInvitationEmail: jest.fn(),
+jest.mock('@pubsweet/component-send-email', () => ({
+  send: jest.fn(),
 }))
+
 const chance = new Chance()
 const reqBody = {
   email: chance.email(),
diff --git a/packages/component-manuscript-manager/src/routes/fragments/notifications/emailCopy.js b/packages/component-manuscript-manager/src/routes/fragments/notifications/emailCopy.js
new file mode 100644
index 0000000000000000000000000000000000000000..c9e4d53a4c9432bdf535165954f872fc077a3f30
--- /dev/null
+++ b/packages/component-manuscript-manager/src/routes/fragments/notifications/emailCopy.js
@@ -0,0 +1,25 @@
+const getEmailCopy = ({ emailType, titleText, expectedDate }) => {
+  let paragraph
+  const hasLink = true
+  switch (emailType) {
+    case 'he-new-version-submitted':
+      paragraph = `A new version of ${titleText} has been submitted.
+        Previous reviewers have been automatically invited to review the manuscript again. Please visit the manuscript details page to see the latest version and any other actions you may need to take.`
+      break
+    case 'submitted-reviewers-after-revision':
+      paragraph = `A new version of ${titleText} has been submitted. As you have reviewed the previous version of this manuscript, I would be grateful if you can review this revised version and submit a review report by ${expectedDate}. You can download the PDF of the revised version and submit your new review from the following URL:`
+      break
+    case 'eic-manuscript-submitted':
+      paragraph = `A new manuscript has been submitted. You can view ${titleText} and take further actions by clicking on the following link:`
+      break
+
+    default:
+      throw new Error(`The ${emailType} email type is not defined.`)
+  }
+
+  return { paragraph, hasLink }
+}
+
+module.exports = {
+  getEmailCopy,
+}
diff --git a/packages/component-manuscript-manager/src/routes/fragments/notifications/notifications.js b/packages/component-manuscript-manager/src/routes/fragments/notifications/notifications.js
new file mode 100644
index 0000000000000000000000000000000000000000..e7deca937409a53ca68ecc925b17f55080b51434
--- /dev/null
+++ b/packages/component-manuscript-manager/src/routes/fragments/notifications/notifications.js
@@ -0,0 +1,176 @@
+const config = require('config')
+const { get } = require('lodash')
+
+const {
+  User,
+  Email,
+  services,
+  Fragment,
+} = require('pubsweet-component-helper-service')
+
+const { getEmailCopy } = require('./emailCopy')
+
+const unsubscribeSlug = config.get('unsubscribe.url')
+
+module.exports = {
+  async sendNotifications({
+    baseUrl,
+    fragment,
+    UserModel,
+    collection,
+    isForEditorInChief,
+    isMajorRecommendation,
+  }) {
+    const fragmentHelper = new Fragment({ fragment })
+    const parsedFragment = await fragmentHelper.getFragmentData({
+      handlingEditor: collection.handlingEditor,
+    })
+    const fragmentAuthors = await fragmentHelper.getAuthorData({ UserModel })
+
+    const subjectBaseText = `${collection.customId}: Manuscript`
+    const titleText = `the manuscript titled "${parsedFragment.title}" by ${
+      fragmentAuthors.submittingAuthor.firstName
+    } ${fragmentAuthors.submittingAuthor.firstName}`
+
+    const email = new Email({
+      type: 'user',
+      content: {
+        signatureName: get(collection, 'handlingEditor.name', 'Hindawi'),
+        ctaLink: services.createUrl(
+          baseUrl,
+          `/projects/${collection.id}/versions/${fragment.id}/details`,
+        ),
+        ctaText: 'MANUSCRIPT DETAILS',
+      },
+    })
+
+    const userHelper = new User({ UserModel })
+    const eic = await userHelper.getEditorInChief()
+    const eicName = `${eic.firstName} ${eic.lastName}`
+
+    sendHandlingEditorEmail({
+      email,
+      eicName,
+      baseUrl,
+      titleText,
+      subjectBaseText,
+      handlingEditor: get(collection, 'handlingEditor', {}),
+    })
+
+    if (isMajorRecommendation) {
+      sendReviewersEmail({
+        email,
+        baseUrl,
+        titleText,
+        fragmentHelper,
+        subjectBaseText,
+      })
+    }
+
+    if (isForEditorInChief) {
+      sendEiCEmail({
+        eic,
+        email,
+        baseUrl,
+        titleText,
+        fragmentHelper,
+        subjectBaseText,
+      })
+    }
+  },
+}
+
+const sendHandlingEditorEmail = ({
+  email,
+  eicName,
+  baseUrl,
+  titleText,
+  handlingEditor,
+  subjectBaseText,
+}) => {
+  const emailType = 'he-new-version-submitted'
+
+  email.toUser = {
+    email: handlingEditor.email,
+    name: `${handlingEditor.name}`,
+  }
+  email.content.unsubscribeLink = services.createUrl(baseUrl, unsubscribeSlug, {
+    id: handlingEditor.id,
+  })
+  email.content.signatureName = eicName
+  email.content.subject = `${subjectBaseText} Update`
+
+  const { html, text } = email.getBody({
+    template: 'notification',
+    ...getEmailCopy({
+      emailType,
+      titleText,
+    }),
+  })
+  email.sendEmail({ html, text })
+}
+
+const sendReviewersEmail = async ({
+  email,
+  baseUrl,
+  titleText,
+  UserModel,
+  fragmentHelper,
+  subjectBaseText,
+}) => {
+  email.content.subject = `${subjectBaseText} Update`
+  const emailType = 'submitted-reviewers-after-revision'
+
+  const reviewers = await fragmentHelper.getReviewers({
+    UserModel,
+    type: 'submitted',
+  })
+
+  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: getEmailCopy({
+        emailType,
+        titleText,
+        expectedDate: services.getExpectedDate({ daysExpected: 14 }),
+      }),
+    })
+
+    email.sendEmail({ html, text })
+  })
+}
+
+const sendEiCEmail = ({ eic, email, baseUrl, titleText, subjectBaseText }) => {
+  const emailType = 'eic-manuscript-submitted'
+
+  email.toUser = {
+    email: eic.email,
+    name: `${eic.firstName} ${eic.lastName}`,
+  }
+
+  email.content.unsubscribeLink = services.createUrl(baseUrl, unsubscribeSlug, {
+    id: eic.id,
+  })
+  email.content.signatureName = 'Hindawi Submission System'
+  email.content.subject = `${subjectBaseText} Submitted`
+
+  const { html, text } = email.getBody({
+    body: getEmailCopy({
+      emailType,
+      titleText,
+    }),
+  })
+  email.sendEmail({ html, text })
+}
diff --git a/packages/component-manuscript-manager/src/routes/fragments/patch.js b/packages/component-manuscript-manager/src/routes/fragments/patch.js
index 7359ed96fea78b83498499ff7fe56b51dfe3bdef..e5620211b15120131466a15bf94ce9404cb5d266 100644
--- a/packages/component-manuscript-manager/src/routes/fragments/patch.js
+++ b/packages/component-manuscript-manager/src/routes/fragments/patch.js
@@ -1,12 +1,14 @@
+const { union, omit } = require('lodash')
+
 const {
   Team,
-  Email,
   services,
   Fragment,
   Collection,
   authsome: authsomeHelper,
 } = require('pubsweet-component-helper-service')
-const { union, omit } = require('lodash')
+
+const notifications = require('./notifications/notifications')
 
 module.exports = models => async (req, res) => {
   const { collectionId, fragmentId } = req.params
@@ -49,7 +51,10 @@ module.exports = models => async (req, res) => {
     const newFragmentBody = {
       ...omit(fragment, ['revision', 'recommendations', 'id']),
       ...fragment.revision,
-      invitations: await fragmentHelper.getInvitationsForSubmittingReviewers(),
+      invitations: fragmentHelper.getInvitations({
+        isAccepted: true,
+        type: 'submitted',
+      }),
       version: fragment.version + 1,
       created: new Date(),
     }
@@ -110,27 +115,13 @@ module.exports = models => async (req, res) => {
     collection.fragments.push(newFragment.id)
     collection.save()
 
-    const parsedFragment = await fragmentHelper.getFragmentData({
-      handlingEditor: collection.handlingEditor,
-    })
-    const authors = await fragmentHelper.getAuthorData({
-      UserModel: models.User,
-    })
-    const email = new Email({
-      authors,
+    notifications.sendNotifications({
+      fragment,
       collection,
-      parsedFragment: { ...parsedFragment, id: fragment.id },
       UserModel: models.User,
       baseUrl: services.getBaseUrl(req),
+      isMajorRecommendation: heRecommendation.recommendation === 'major',
     })
-    email.setupNewVersionSubmittedEmail()
-
-    if (heRecommendation.recommendation === 'major') {
-      email.sendNewVersionSubmittedReviewersEmail({
-        invitations: newFragment.invitations,
-        newFragmentId: newFragment.id,
-      })
-    }
 
     return res.status(200).json(newFragment)
   } catch (e) {
diff --git a/packages/component-manuscript-manager/src/routes/fragments/post.js b/packages/component-manuscript-manager/src/routes/fragments/post.js
index b54399b0cc006f469863bbfabaaecb0c8bab3150..c8588d6fd15003aa675ef1b5efc75495bd049aa0 100644
--- a/packages/component-manuscript-manager/src/routes/fragments/post.js
+++ b/packages/component-manuscript-manager/src/routes/fragments/post.js
@@ -1,10 +1,10 @@
 const {
-  Email,
-  Fragment,
   services,
   authsome: authsomeHelper,
 } = require('pubsweet-component-helper-service')
 
+const notifications = require('./notifications/notifications')
+
 module.exports = models => async (req, res) => {
   const { collectionId, fragmentId } = req.params
   let collection, fragment
@@ -31,25 +31,16 @@ module.exports = models => async (req, res) => {
     fragment.submitted = Date.now()
     fragment = await fragment.save()
 
-    const fragmentHelper = new Fragment({ fragment })
-    const parsedFragment = await fragmentHelper.getFragmentData({
-      handlingEditor: collection.handlingEditor,
-    })
-    const authors = await fragmentHelper.getAuthorData({
-      UserModel: models.User,
-    })
+    collection.status = 'submitted'
+    collection.save()
 
-    const email = new Email({
-      authors,
+    notifications.sendNotifications({
+      fragment,
       collection,
-      parsedFragment,
       UserModel: models.User,
+      isForEditorInChief: true,
       baseUrl: services.getBaseUrl(req),
     })
-    email.setupManuscriptSubmittedEmail()
-
-    collection.status = 'submitted'
-    collection.save()
 
     return res.status(200).json(fragment)
   } catch (e) {
diff --git a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/emailCopy.js b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/emailCopy.js
new file mode 100644
index 0000000000000000000000000000000000000000..5b46e6c1c5e482f4eb6eb63491d7385700ac9ead
--- /dev/null
+++ b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/emailCopy.js
@@ -0,0 +1,74 @@
+const getEmailCopy = ({
+  emailType,
+  titleText,
+  comments = '',
+  targetUserName = '',
+}) => {
+  let paragraph
+  let hasLink = true
+  switch (emailType) {
+    case 'author-request-to-revision':
+      paragraph = `In order for ${titleText} to proceed to publication, there needs to be a revision. <br/><br/>
+      ${comments}<br/><br/>
+        For more information about what is required, please visit the manuscript details page.`
+      break
+    case 'author-manuscript-rejected':
+      paragraph = `I am sorry to inform you that ${titleText} has been rejected for publication. <br/><br/>
+    ${comments}<br/><br/>`
+      hasLink = false
+      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
+    case 'he-manuscript-rejected':
+      hasLink = false
+      paragraph = `Thank you for your recommendation to reject ${titleText} based on the reviews you received.<br/><br/>
+      I can confirm this article has now been rejected.`
+      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 'he-manuscript-return-with-comments':
+      hasLink = false
+      paragraph = `Thank you for your recommendation for ${titleText} based on the reviews you received.<br/><br/>
+      ${comments}<br/><br/>`
+      break
+    case 'accepted-reviewers-after-recommendation':
+      hasLink = false
+      paragraph = `I appreciate any time you may have spent reviewing ${titleText}. However, an editorial decision has been made and the review of this manuscript is now complete. I apologize for any inconvenience. <br/>
+      If you have comments on this manuscript you believe the Editor should see, please email them to Hindawi as soon as possible. <br/>
+      Thank you for your interest and I hope you will consider reviewing for Hindawi again.`
+      break
+    case 'pending-reviewers-after-he-recommendation':
+      hasLink = false
+      paragraph = `An editorial decision has been made regarding ${titleText}. So, you do not need to proceed with the review of this manuscript. <br/><br/>
+      If you have comments on this manuscript you believe the Editor should see, please email them to Hindawi as soon as possible.`
+      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 'submitted-reviewers-after-reject':
+      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 has now been rejected.<br/><br/>
+      If you have any queries about this decision, then please email them to Hindawi as soon as possible.`
+      break
+    case 'review-submitted':
+      paragraph = `We are pleased to inform you that Dr. ${targetUserName} has submitted a review for ${titleText}.`
+      break
+    default:
+      throw new Error(`The ${emailType} email type is not defined.`)
+  }
+
+  return { paragraph, hasLink }
+}
+
+module.exports = {
+  getEmailCopy,
+}
diff --git a/packages/component-manuscript-manager/src/notifications/notifications.js b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/notifications.js
similarity index 72%
rename from packages/component-manuscript-manager/src/notifications/notifications.js
rename to packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/notifications.js
index c0fea465a0354ee0b3c5674c58c8df5c0ecb4cc4..d5302e1fe851ccf99c59bc40c3957d8121136821 100644
--- a/packages/component-manuscript-manager/src/notifications/notifications.js
+++ b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/notifications.js
@@ -8,6 +8,8 @@ const {
   Fragment,
 } = require('pubsweet-component-helper-service')
 
+const { getEmailCopy } = require('./emailCopy')
+
 const unsubscribeSlug = config.get('unsubscribe.url')
 
 module.exports = {
@@ -16,7 +18,7 @@ module.exports = {
     fragment,
     UserModel,
     collection,
-    sourceUserName,
+    targetUserName,
     isEditorInChief,
     newRecommendation,
   }) {
@@ -25,20 +27,21 @@ module.exports = {
       handlingEditor: collection.handlingEditor,
     })
     const fragmentAuthors = await fragmentHelper.getAuthorData({ UserModel })
+
     const subjectBaseText = `${collection.customId}: Manuscript`
+    const titleText = `the manuscript titled "${parsedFragment.title}" by ${
+      fragmentAuthors.submittingAuthor.firstName
+    } ${fragmentAuthors.submittingAuthor.firstName}`
+
     const email = new Email({
       type: 'user',
       content: {
-        comments: '',
-        sourceUserName,
         signatureName: get(collection, 'handlingEditor.name', 'Hindawi'),
-        titleText: `the manuscript titled "${parsedFragment.title}" by ${
-          fragmentAuthors.submittingAuthor.firstName
-        } ${fragmentAuthors.submittingAuthor.firstName}`,
-        detailsLink: services.createUrl(
+        ctaLink: services.createUrl(
           baseUrl,
           `/projects/${collection.id}/versions/${fragment.id}/details`,
         ),
+        ctaText: 'MANUSCRIPT DETAILS',
       },
     })
 
@@ -46,6 +49,7 @@ module.exports = {
     const { firstName, lastName } = await userHelper.getEditorInChief()
     const eicName = `${firstName} ${lastName}`
 
+    let comments
     if (isEditorInChief) {
       const eicComments = chain(newRecommendation)
         .get('comments')
@@ -53,7 +57,7 @@ module.exports = {
         .get('content')
         .value()
 
-      email.content.comments = eicComments
+      comments = eicComments
     }
 
     if (isEditorInChief || newRecommendation.recommendationType === 'review') {
@@ -61,6 +65,9 @@ module.exports = {
         email,
         eicName,
         baseUrl,
+        comments,
+        titleText,
+        targetUserName,
         subjectBaseText,
         handlingEditor: get(collection, 'handlingEditor', {}),
         recommendation: newRecommendation.recommendation,
@@ -72,6 +79,7 @@ module.exports = {
       sendAuthorsEmail({
         email,
         baseUrl,
+        titleText,
         parsedFragment,
         fragmentAuthors,
         isEditorInChief,
@@ -82,10 +90,13 @@ module.exports = {
       sendReviewersEmail({
         email,
         baseUrl,
+        UserModel,
+        titleText,
         fragmentHelper,
         isEditorInChief,
         subjectBaseText,
         recommendation: newRecommendation.recommendation,
+        handlingEditorName: get(collection, 'handlingEditor.name', 'Faraday'),
       })
     }
   },
@@ -95,7 +106,10 @@ const sendHandlingEditorEmail = ({
   email,
   eicName,
   baseUrl,
+  comments,
+  titleText,
   handlingEditor,
+  targetUserName,
   recommendation,
   subjectBaseText,
   recommendationType,
@@ -103,7 +117,7 @@ const sendHandlingEditorEmail = ({
   let emailType
   if (recommendationType === 'review') {
     email.content.subject = `${subjectBaseText} Review`
-    emailType = 'review-submitted'
+    emailType = 'he-review-submitted'
   } else {
     email.content.subject = `${subjectBaseText} Decision`
     switch (recommendation) {
@@ -129,30 +143,38 @@ const sendHandlingEditorEmail = ({
     id: handlingEditor.id,
   })
   email.content.signatureName = eicName
-  const { html, text } = email.getBody({ emailType })
+  const { html, text } = email.getBody({
+    body: getEmailCopy({
+      emailType,
+      titleText,
+      comments,
+      targetUserName,
+    }),
+  })
   email.sendEmail({ html, text })
 }
 
 const sendAuthorsEmail = async ({
   email,
   baseUrl,
+  titleText,
   recommendation,
   isEditorInChief,
   subjectBaseText,
   fragmentAuthors,
   parsedFragment: { heRecommendation, newComments },
 }) => {
-  let emailType, authors
+  let emailType, authors, comments
 
   if (isEditorInChief) {
-    const comments = get(heRecommendation, 'comments', [])
-    if (comments.length) {
-      const publicComment = comments.find(comm => comm.public)
+    const heComments = get(heRecommendation, 'comments', [])
+    if (heComments.length) {
+      const publicComment = heComments.find(comm => comm.public)
       const content = get(publicComment, 'content')
       if (!content) {
         throw new Error('a public comment cannot be without content')
       }
-      email.content.comments = `Reason & Details: "${content}"`
+      comments = `Reason & Details: "${content}"`
     }
 
     if (recommendation === 'publish') {
@@ -165,12 +187,24 @@ const sendAuthorsEmail = async ({
 
     authors = fragmentAuthors.activeAuthors.map(author => ({
       ...author,
-      emailType,
+      ...getEmailCopy({
+        emailType,
+        titleText,
+        comments,
+      }),
     }))
   } else {
-    email.content.comments = newComments
     emailType = 'author-request-to-revision'
-    authors = [{ ...fragmentAuthors.submittingAuthor, emailType }]
+    authors = [
+      {
+        ...fragmentAuthors.submittingAuthor,
+        ...getEmailCopy({
+          emailType,
+          titleText,
+          comments: newComments,
+        }),
+      },
+    ]
   }
 
   authors.forEach(author => {
@@ -185,7 +219,12 @@ const sendAuthorsEmail = async ({
         id: author.id,
       },
     )
-    const { html, text } = email.getBody({ emailType: author.emailType })
+    const { html, text } = email.getBody({
+      body: {
+        paragraph: author.paragraph,
+      },
+      hasLink: author.hasLink,
+    })
     email.sendEmail({ html, text })
   })
 }
@@ -194,6 +233,7 @@ const sendReviewersEmail = async ({
   email,
   baseUrl,
   eicName,
+  titleText,
   UserModel,
   fragmentHelper,
   recommendation,
@@ -203,28 +243,39 @@ const sendReviewersEmail = async ({
 }) => {
   let reviewers
   if (isEditorInChief) {
-    email.content.subject = `${email.content.subject} Decision`
+    email.content.subject = `${subjectBaseText} Decision`
+    const emailType =
+      recommendation === 'publish'
+        ? 'submitting-reviewers-after-publish'
+        : 'submitting-reviewers-after-reject'
 
     reviewers = (await fragmentHelper.getReviewers({
       UserModel,
       type: 'submitting',
     })).map(rev => ({
       ...rev,
-      emailType: 'submitted-reviewers-after-recommendation',
+      emailType,
+      ...getEmailCopy({
+        emailType,
+        titleText,
+      }),
     }))
-
     email.content.signatureName = eicName
   } else {
     email.content.signatureName = handlingEditorName
-    email.contet.subject = `${subjectBaseText} ${getSubjectByRecommendation(
+    email.content.subject = `${subjectBaseText} ${getSubjectByRecommendation(
       recommendation,
     )}`
+
     const acceptedReviewers = (await fragmentHelper.getReviewers({
       UserModel,
       type: 'accepted',
     })).map(rev => ({
       ...rev,
-      emailType: 'accepted-reviewers-after-recommendation',
+      ...getEmailCopy({
+        emailType: 'accepted-reviewers-after-recommendation',
+        titleText,
+      }),
     }))
 
     const pendingReviewers = (await fragmentHelper.getReviewers({
@@ -232,7 +283,10 @@ const sendReviewersEmail = async ({
       type: 'pending',
     })).map(rev => ({
       ...rev,
-      emailType: 'pending-reviewers-after-recommendation',
+      ...getEmailCopy({
+        emailType: 'pending-reviewers-after-recommendation',
+        titleText,
+      }),
     }))
 
     reviewers = [...acceptedReviewers, ...pendingReviewers]
@@ -250,7 +304,10 @@ const sendReviewersEmail = async ({
         id: reviewer.id,
       },
     )
-    const { html, text } = email.getBody({ emailType: reviewer.emailType })
+    const { html, text } = email.getBody({
+      body: { paragraph: reviewer.paragraph },
+      hasLink: reviewer.hasLink,
+    })
     email.sendEmail({ html, text })
   })
 }
diff --git a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/patch.js b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/patch.js
index c9ea11971f50bf100aa400936dc46ead76ed89c5..1e0e4f2425d884b64e5e0ad3c8616d83c371e8a3 100644
--- a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/patch.js
+++ b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/patch.js
@@ -1,12 +1,10 @@
 const {
-  // Email,
   services,
   authsome: authsomeHelper,
-  // Fragment,
   Collection,
 } = require('pubsweet-component-helper-service')
 
-const notifications = require('../../notifications/notifications')
+const notifications = require('./notifications/notifications')
 
 module.exports = models => async (req, res) => {
   const { collectionId, fragmentId, recommendationId } = req.params
@@ -48,30 +46,8 @@ module.exports = models => async (req, res) => {
 
     Object.assign(recommendation, req.body)
     recommendation.updatedOn = Date.now()
-    if (req.body.submittedOn) {
-      // const fragmentHelper = new Fragment({ fragment })
-      // const parsedFragment = await fragmentHelper.getFragmentData({
-      //   handlingEditor: collection.handlingEditor,
-      // })
-      // const baseUrl = services.getBaseUrl(req)
-      const collectionHelper = new Collection({ collection })
-
-      // const authors = await fragmentHelper.getAuthorData({
-      //   UserModel,
-      // })
-
-      // const email = new Email({
-      //   UserModel,
-      //   collection,
-      //   parsedFragment,
-      //   baseUrl,
-      //   authors,
-      // })
 
-      // email.setupHandlingEditorEmail({
-      //   reviewSubmitted: true,
-      //   reviewerName: `${user.firstName} ${user.lastName}`,
-      // })
+    if (req.body.submittedOn) {
       notifications.sendNotifications({
         fragment,
         collection,
@@ -79,13 +55,17 @@ module.exports = models => async (req, res) => {
         UserModel: models.User,
         baseUrl: services.getBaseUrl(req),
         newRecommendation: recommendation,
-        sourceUserName: `${user.firstName} ${user.lastName}`,
+        targetUserName: `${user.firstName} ${user.lastName}`,
       })
 
-      if (['underReview'].includes(collection.status))
+      if (['underReview'].includes(collection.status)) {
+        const collectionHelper = new Collection({ collection })
         collectionHelper.updateStatus({ newStatus: 'reviewCompleted' })
+      }
     }
-    await fragment.save()
+
+    fragment.save()
+
     return res.status(200).json(recommendation)
   } catch (e) {
     const notFoundError = await services.handleNotFoundError(e, 'Item')
diff --git a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/post.js b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/post.js
index 4ce2374fbf397e0780c9fd2b1dc6d33f257050e6..61b5cc07ca41eac18b8478acf375d291640defd3 100644
--- a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/post.js
+++ b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/post.js
@@ -7,7 +7,7 @@ const {
   Collection,
 } = require('pubsweet-component-helper-service')
 
-const notifications = require('../../notifications/notifications')
+const notifications = require('./notifications/notifications')
 
 module.exports = models => async (req, res) => {
   const { recommendation, comments, recommendationType } = req.body
diff --git a/packages/component-manuscript-manager/src/tests/fragments/patch.test.js b/packages/component-manuscript-manager/src/tests/fragments/patch.test.js
index 556203add45f77723b87e974158c501d53cd2e46..f4e2147a5604bf4f77e0782fdd1f33cb28ec9f58 100644
--- a/packages/component-manuscript-manager/src/tests/fragments/patch.test.js
+++ b/packages/component-manuscript-manager/src/tests/fragments/patch.test.js
@@ -6,8 +6,8 @@ const fixturesService = require('pubsweet-component-fixture-service')
 const requests = require('../requests')
 
 const { Model, fixtures } = fixturesService
-jest.mock('pubsweet-component-mail-service', () => ({
-  sendNotificationEmail: jest.fn(),
+jest.mock('@pubsweet/component-send-email', () => ({
+  send: jest.fn(),
 }))
 const reqBody = {}
 
diff --git a/packages/component-manuscript-manager/src/tests/fragments/post.test.js b/packages/component-manuscript-manager/src/tests/fragments/post.test.js
index 07b6ff7a80ec6024f7e9126551c001eeeb32fad9..d1446faf3747786d926728c791f4cce64659cddb 100644
--- a/packages/component-manuscript-manager/src/tests/fragments/post.test.js
+++ b/packages/component-manuscript-manager/src/tests/fragments/post.test.js
@@ -6,9 +6,8 @@ const fixturesService = require('pubsweet-component-fixture-service')
 const requests = require('../requests')
 
 const { Model, fixtures } = fixturesService
-jest.mock('pubsweet-component-mail-service', () => ({
-  sendNotificationEmail: jest.fn(),
-  sendSimpleEmail: jest.fn(),
+jest.mock('@pubsweet/component-send-email', () => ({
+  send: jest.fn(),
 }))
 const reqBody = {}
 
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 9013b742480d37eba74bd32157705009082b45e5..0f0f048e62835ecbd5d6c9df1f36ad3de740b183 100644
--- a/packages/component-manuscript-manager/src/tests/fragmentsRecommendations/post.test.js
+++ b/packages/component-manuscript-manager/src/tests/fragmentsRecommendations/post.test.js
@@ -8,9 +8,10 @@ const requests = require('../requests')
 
 const { Model, fixtures } = fixturesService
 const chance = new Chance()
-jest.mock('pubsweet-component-mail-service', () => ({
-  sendNotificationEmail: jest.fn(),
+jest.mock('@pubsweet/component-send-email', () => ({
+  send: jest.fn(),
 }))
+
 const reqBody = {
   recommendation: 'accept',
   comments: [