diff --git a/packages/component-fixture-manager/src/fixtures/fragments.js b/packages/component-fixture-manager/src/fixtures/fragments.js
index 2ee8c78db32d02ae01404cabaaae3ae88aecb113..10fcf908ed077f7ecda22e87cb745af8b0a539f1 100644
--- a/packages/component-fixture-manager/src/fixtures/fragments.js
+++ b/packages/component-fixture-manager/src/fixtures/fragments.js
@@ -86,6 +86,7 @@ const fragments = {
     ],
     authors: [
       {
+        email: chance.email(),
         id: submittingAuthor.id,
         isSubmitting: true,
         isCorresponding: false,
@@ -124,6 +125,7 @@ const fragments = {
     },
     authors: [
       {
+        email: chance.email(),
         id: submittingAuthor.id,
         isSubmitting: true,
         isCorresponding: false,
@@ -162,6 +164,7 @@ const fragments = {
     },
     authors: [
       {
+        email: chance.email(),
         id: submittingAuthor.id,
         isSubmitting: true,
         isCorresponding: false,
diff --git a/packages/component-helper-service/src/services/Email.js b/packages/component-helper-service/src/services/Email.js
index 7241792473c594738d65210ccfe98b4e0f08e91f..15d06ecb278aac32ee6928c6eced4c1bf74bc2aa 100644
--- a/packages/component-helper-service/src/services/Email.js
+++ b/packages/component-helper-service/src/services/Email.js
@@ -347,6 +347,30 @@ class Email {
       },
     })
   }
+
+  async setupManuscriptSubmittedEmail() {
+    const {
+      baseUrl,
+      UserModel,
+      collection,
+      parsedFragment: { id, title },
+      authors: { submittingAuthor: { firstName = '', lastName = '' } },
+    } = this
+
+    const userHelper = new User({ UserModel })
+    const eic = await userHelper.getEditorInChief()
+
+    mailService.sendSimpleEmail({
+      toEmail: eic.email,
+      emailType: 'manuscript-submitted',
+      dashboardUrl: baseUrl,
+      meta: {
+        collection,
+        fragment: { id, authorName: `${firstName} ${lastName}`, title },
+        eicName: `${eic.firstName} ${eic.lastName}`,
+      },
+    })
+  }
 }
 
 const getSubject = recommendation =>
diff --git a/packages/component-mail-service/src/Mail.js b/packages/component-mail-service/src/Mail.js
index d40d99d1f2803362450ef95ec51552948ce6e791..39cff7d046e3704ae6abdb3a3cc728672bb1fe38 100644
--- a/packages/component-mail-service/src/Mail.js
+++ b/packages/component-mail-service/src/Mail.js
@@ -7,10 +7,10 @@ const resetPath = config.get('invite-reset-password.url')
 
 module.exports = {
   sendSimpleEmail: async ({
-    toEmail,
-    user,
-    emailType,
-    dashboardUrl,
+    toEmail = '',
+    user = {},
+    emailType = '',
+    dashboardUrl = '',
     meta = {},
   }) => {
     let subject, textBody
@@ -117,6 +117,26 @@ module.exports = {
         textBody = `${replacements.headline}`
         emailTemplate = 'noCTA'
         break
+      case 'manuscript-submitted':
+        subject = `${meta.collection.customId}: Manuscript Submitted`
+        replacements.previewText = 'A new manuscript has been submitted'
+        replacements.headline = `A new manuscript has been submitted.`
+        replacements.paragraph = `You can view the full manuscript titled "${
+          meta.fragment.title
+        }" by ${
+          meta.fragment.authorName
+        } and take further actions by clicking on the following link:`
+        replacements.buttonText = 'MANUSCRIPT DETAILS'
+        replacements.url = helpers.createUrl(
+          dashboardUrl,
+          `/projects/${meta.collection.id}/versions/${
+            meta.fragment.id
+          }/details`,
+        )
+        textBody = `${replacements.headline} ${replacements.paragraph} ${
+          replacements.url
+        } ${replacements.buttonText}`
+        break
       default:
         subject = 'Welcome to Hindawi!'
         break
diff --git a/packages/component-manuscript-manager/src/Fragments.js b/packages/component-manuscript-manager/src/Fragments.js
index 9e3569166d7dd7e7e76f9082412ab3bc8219c16a..01e11a93582bdc5ff37497d2bb7a7c6a980b68c0 100644
--- a/packages/component-manuscript-manager/src/Fragments.js
+++ b/packages/component-manuscript-manager/src/Fragments.js
@@ -9,7 +9,7 @@ const Fragments = app => {
   })
   /**
    * @api {patch} /api/collections/:collectionId/fragments/:fragmentId/submit Submit a revision for a manuscript
-   * @apiGroup FragmentsRecommendations
+   * @apiGroup Fragments
    * @apiParam {collectionId} collectionId Collection id
    * @apiParam {fragmentId} fragmentId Fragment id
    * @apiSuccessExample {json} Success
@@ -28,6 +28,27 @@ const Fragments = app => {
     authBearer,
     require(`${routePath}/patch`)(app.locals.models),
   )
+  /**
+   * @api {post} /api/collections/:collectionId/fragments/:fragmentId/submit Submit a manuscript
+   * @apiGroup Fragments
+   * @apiParam {collectionId} collectionId Collection id
+   * @apiParam {fragmentId} fragmentId Fragment id
+   * @apiSuccessExample {json} Success
+   *   HTTP/1.1 200 OK
+   *   {
+   *
+   *   }
+   * @apiErrorExample {json} Invite user errors
+   *    HTTP/1.1 403 Forbidden
+   *    HTTP/1.1 400 Bad Request
+   *    HTTP/1.1 404 Not Found
+   *    HTTP/1.1 500 Internal Server Error
+   */
+  app.post(
+    `${basePath}`,
+    authBearer,
+    require(`${routePath}/post`)(app.locals.models),
+  )
 }
 
 module.exports = Fragments
diff --git a/packages/component-manuscript-manager/src/routes/fragments/post.js b/packages/component-manuscript-manager/src/routes/fragments/post.js
new file mode 100644
index 0000000000000000000000000000000000000000..d0b5b18f6d4592f681bcd14298c8cedd5c194c0d
--- /dev/null
+++ b/packages/component-manuscript-manager/src/routes/fragments/post.js
@@ -0,0 +1,58 @@
+const {
+  Email,
+  Fragment,
+  services,
+  authsome: authsomeHelper,
+} = require('pubsweet-component-helper-service')
+
+module.exports = models => async (req, res) => {
+  const { collectionId, fragmentId } = req.params
+  let collection, fragment
+
+  try {
+    collection = await models.Collection.find(collectionId)
+    if (!collection.fragments.includes(fragmentId))
+      return res.status(400).json({
+        error: `Collection and fragment do not match.`,
+      })
+    fragment = await models.Fragment.find(fragmentId)
+
+    const authsome = authsomeHelper.getAuthsome(models)
+    const target = {
+      fragment,
+      path: req.route.path,
+    }
+    const canPost = await authsome.can(req.user, 'POST', target)
+    if (!canPost)
+      return res.status(403).json({
+        error: 'Unauthorized.',
+      })
+
+    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,
+    })
+
+    const email = new Email({
+      authors,
+      collection,
+      parsedFragment,
+      UserModel: models.User,
+      baseUrl: services.getBaseUrl(req),
+    })
+    email.setupManuscriptSubmittedEmail()
+
+    return res.status(200).json(fragment)
+  } catch (e) {
+    const notFoundError = await services.handleNotFoundError(e, 'Item')
+    return res.status(notFoundError.status).json({
+      error: notFoundError.message,
+    })
+  }
+}
diff --git a/packages/component-manuscript-manager/src/tests/fragments/post.test.js b/packages/component-manuscript-manager/src/tests/fragments/post.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..1da5c72f731cdc11512706c2709d014dd2ed1930
--- /dev/null
+++ b/packages/component-manuscript-manager/src/tests/fragments/post.test.js
@@ -0,0 +1,86 @@
+process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
+process.env.SUPPRESS_NO_CONFIG_WARNING = true
+
+const cloneDeep = require('lodash/cloneDeep')
+const fixturesService = require('pubsweet-component-fixture-service')
+const requests = require('../requests')
+
+const { Model, fixtures } = fixturesService
+jest.mock('pubsweet-component-mail-service', () => ({
+  sendNotificationEmail: jest.fn(),
+}))
+const reqBody = {}
+
+const path = '../routes/fragments/post'
+const route = {
+  path: '/api/collections/:collectionId/fragments/:fragmentId/submit',
+}
+describe('Post fragments route handler', () => {
+  let testFixtures = {}
+  let body = {}
+  let models
+  beforeEach(() => {
+    testFixtures = cloneDeep(fixtures)
+    body = cloneDeep(reqBody)
+    models = Model.build(testFixtures)
+  })
+  it('should return success when the parameters are correct', async () => {
+    const { user } = testFixtures.users
+    const { collection } = testFixtures.collections
+    const { fragment } = testFixtures.fragments
+    const res = await requests.sendRequest({
+      body,
+      userId: user.id,
+      models,
+      route,
+      path,
+      params: {
+        collectionId: collection.id,
+        fragmentId: fragment.id,
+      },
+    })
+
+    expect(res.statusCode).toBe(200)
+  })
+  it('should return an error when the fragmentId does not match the collectionId', async () => {
+    const { user } = testFixtures.users
+    const { collection } = testFixtures.collections
+    const { noParentFragment } = testFixtures.fragments
+
+    const res = await requests.sendRequest({
+      body,
+      userId: user.id,
+      models,
+      route,
+      path,
+      params: {
+        collectionId: collection.id,
+        fragmentId: noParentFragment.id,
+      },
+    })
+
+    expect(res.statusCode).toBe(400)
+    const data = JSON.parse(res._getData())
+    expect(data.error).toEqual('Collection and fragment do not match.')
+  })
+  it('should return an error when the collection does not exist', async () => {
+    const { user } = testFixtures.users
+    const { fragment } = testFixtures.fragments
+
+    const res = await requests.sendRequest({
+      body,
+      userId: user.id,
+      models,
+      route,
+      path,
+      params: {
+        collectionId: 'invalid-id',
+        fragmentId: fragment.id,
+      },
+    })
+
+    expect(res.statusCode).toBe(404)
+    const data = JSON.parse(res._getData())
+    expect(data.error).toEqual('Item not found')
+  })
+})
diff --git a/packages/xpub-faraday/config/authsome-helpers.js b/packages/xpub-faraday/config/authsome-helpers.js
index ad75355dd14fd8f26a70e2f75bb2f8c74a87054d..8b5a135a30aa8f7bc660d518664db6b32001017a 100644
--- a/packages/xpub-faraday/config/authsome-helpers.js
+++ b/packages/xpub-faraday/config/authsome-helpers.js
@@ -4,7 +4,9 @@ const config = require('config')
 
 const statuses = config.get('statuses')
 
+const keysToOmit = ['email', 'id']
 const publicStatusesPermissions = ['author', 'reviewer']
+const authorAllowedStatuses = ['revisionRequested', 'rejected', 'accepted']
 
 const parseAuthorsData = (coll, matchingCollPerm) => {
   if (['reviewer'].includes(matchingCollPerm.permission)) {
@@ -124,6 +126,55 @@ const hasFragmentInDraft = async ({ object, Fragment }) => {
   return isInDraft(fragment)
 }
 
+const filterAuthorRecommendationData = recommendation => {
+  const { comments } = recommendation
+  return {
+    ...recommendation,
+    comments: comments ? comments.filter(c => c.public) : [],
+  }
+}
+
+const stripeCollectionByRole = (coll = {}, role = '') => {
+  if (role === 'author') {
+    const { handlingEditor } = coll
+
+    if (!authorAllowedStatuses.includes(coll.status)) {
+      coll = {
+        ...coll,
+        handlingEditor: handlingEditor && {
+          ...omit(handlingEditor, keysToOmit),
+          name: 'Assigned',
+        },
+      }
+    }
+  }
+  return coll
+}
+
+const stripeFragmentByRole = (fragment = {}, role = '', user = {}) => {
+  const { recommendations, files, authors } = fragment
+  switch (role) {
+    case 'author':
+      return {
+        ...fragment,
+        recommendations: recommendations
+          ? recommendations.map(filterAuthorRecommendationData)
+          : [],
+      }
+    case 'reviewer':
+      return {
+        ...fragment,
+        files: omit(files, ['coverLetter']),
+        authors: authors.map(a => omit(a, ['email'])),
+        recommendations: recommendations
+          ? recommendations.filter(r => r.userId === user.id)
+          : [],
+      }
+    default:
+      return fragment
+  }
+}
+
 module.exports = {
   filterObjectData,
   parseAuthorsData,
@@ -137,4 +188,6 @@ module.exports = {
   hasPermissionForObject,
   isInDraft,
   hasFragmentInDraft,
+  stripeCollectionByRole,
+  stripeFragmentByRole,
 }
diff --git a/packages/xpub-faraday/config/authsome-mode.js b/packages/xpub-faraday/config/authsome-mode.js
index 960e0bede30325e9d0dec6bc33e6762880b77e8e..2aada0e12aef4d742f83a5847ae150a6a58079fa 100644
--- a/packages/xpub-faraday/config/authsome-mode.js
+++ b/packages/xpub-faraday/config/authsome-mode.js
@@ -1,5 +1,5 @@
 const config = require('config')
-const { get, pickBy, omit } = require('lodash')
+const { get, pickBy } = require('lodash')
 
 const statuses = config.get('statuses')
 const helpers = require('./authsome-helpers')
@@ -103,9 +103,13 @@ async function applyAuthenticatedUserPolicy(user, operation, object, context) {
               collection.fragments.includes(p.objectId),
           )
           const visibleStatus = get(statuses, `${status}.${role}.label`)
+          const parsedCollection = helpers.stripeCollectionByRole(
+            collection,
+            role,
+          )
 
           return {
-            ...collection,
+            ...parsedCollection,
             visibleStatus,
           }
         },
@@ -113,11 +117,7 @@ async function applyAuthenticatedUserPolicy(user, operation, object, context) {
     }
 
     if (get(object, 'type') === 'fragment') {
-      if (helpers.isOwner({ user, object })) {
-        return true
-      }
-
-      if (helpers.isInDraft(object)) {
+      if (helpers.isInDraft(object) && !helpers.isOwner({ user, object })) {
         return false
       }
 
@@ -133,17 +133,8 @@ async function applyAuthenticatedUserPolicy(user, operation, object, context) {
       if (!permission) return false
 
       return {
-        filter: fragment => {
-          // handle other roles
-          if (permission.role === 'reviewer') {
-            fragment.files = omit(fragment.files, ['coverLetter'])
-            fragment.authors = fragment.authors.map(a => omit(a, ['email']))
-            fragment.recommendations = fragment.recommendations
-              ? fragment.recommendations.filter(r => r.userId === user.id)
-              : []
-          }
-          return fragment
-        },
+        filter: fragment =>
+          helpers.stripeFragmentByRole(fragment, permission.role, user),
       }
     }
 
@@ -167,7 +158,7 @@ async function applyAuthenticatedUserPolicy(user, operation, object, context) {
   }
 
   if (operation === 'POST') {
-    // allow everytone to create manuscripts and versions
+    // allow everyone to create manuscripts and versions
     if (createPaths.includes(object.path)) {
       return true
     }
@@ -192,6 +183,14 @@ async function applyAuthenticatedUserPolicy(user, operation, object, context) {
         roles: ['reviewer', 'handlingEditor'],
       })
     }
+
+    // allow owner to submit a manuscript
+    if (
+      get(object, 'path') ===
+      '/api/collections/:collectionId/fragments/:fragmentId/submit'
+    ) {
+      return helpers.isOwner({ user, object: object.fragment })
+    }
   }
 
   if (operation === 'PATCH') {
diff --git a/packages/xpub-faraday/config/test.js b/packages/xpub-faraday/config/test.js
new file mode 100644
index 0000000000000000000000000000000000000000..9950c9b354fa8710a4f043a07ac2b86a3cf6bd2f
--- /dev/null
+++ b/packages/xpub-faraday/config/test.js
@@ -0,0 +1,3 @@
+const defaultConfig = require('xpub-faraday/config/default')
+
+module.exports = defaultConfig
diff --git a/packages/xpub-faraday/package.json b/packages/xpub-faraday/package.json
index 2460482894ba362cf6d2356471ae669c9c9c71b8..e4e829deab3a05be7c02ee7c4bd237ed68d18ca0 100644
--- a/packages/xpub-faraday/package.json
+++ b/packages/xpub-faraday/package.json
@@ -63,6 +63,7 @@
     "file-loader": "^1.1.5",
     "html-webpack-plugin": "^2.24.0",
     "joi-browser": "^10.0.6",
+    "jest": "^22.1.1",
     "react-hot-loader": "^3.1.1",
     "string-replace-loader": "^1.3.0",
     "style-loader": "^0.19.0",
@@ -71,6 +72,10 @@
     "webpack-dev-middleware": "^1.12.0",
     "webpack-hot-middleware": "^2.20.0"
   },
+  "jest": {
+    "verbose": true,
+    "testRegex": "/tests/.*.test.js$"
+  },
   "scripts": {
     "setupdb": "pubsweet setupdb ./",
     "start": "pubsweet start",
@@ -79,6 +84,8 @@
     "start-now":
       "echo $secret > config/local-development.json && npm run server",
     "build": "NODE_ENV=production pubsweet build",
-    "clean": "rm -rf node_modules"
+    "clean": "rm -rf node_modules",
+    "debug": "pgrep -f startup/start.js | xargs kill -sigusr1",
+    "test": "jest"
   }
 }
diff --git a/packages/xpub-faraday/tests/authsome-helpers.test.js b/packages/xpub-faraday/tests/authsome-helpers.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..8999b892b2b80a1ef5b92ffa35f8f823d84f9580
--- /dev/null
+++ b/packages/xpub-faraday/tests/authsome-helpers.test.js
@@ -0,0 +1,117 @@
+const { cloneDeep, get } = require('lodash')
+const fixturesService = require('pubsweet-component-fixture-service')
+const ah = require('../config/authsome-helpers')
+
+describe('Authsome Helpers', () => {
+  let testFixtures = {}
+  beforeEach(() => {
+    testFixtures = cloneDeep(fixturesService.fixtures)
+  })
+  it('stripeCollection - should return collection', () => {
+    const { collection } = testFixtures.collections
+    const result = ah.stripeCollectionByRole(collection)
+    expect(result).toBeTruthy()
+  })
+  it('stripeFragment - should return fragment', () => {
+    const { fragment } = testFixtures.fragments
+    const result = ah.stripeFragmentByRole(fragment)
+    expect(result).toBeTruthy()
+  })
+
+  it('stripeCollection - author should not see HE name before recommendation made', () => {
+    const { collection } = testFixtures.collections
+    collection.status = 'underReview'
+
+    const result = ah.stripeCollectionByRole(collection, 'author')
+    const { handlingEditor = {} } = result
+
+    expect(handlingEditor.email).toBeFalsy()
+    expect(handlingEditor.name).toEqual('Assigned')
+  })
+
+  it('stripeCollection - author should see HE name after recommendation made', () => {
+    const { collection } = testFixtures.collections
+    collection.status = 'revisionRequested'
+
+    const result = ah.stripeCollectionByRole(collection, 'author')
+    const { handlingEditor = {} } = result
+
+    expect(handlingEditor.name).not.toEqual('Assigned')
+  })
+
+  it('stripeCollection - other user than author should see HE name before recommendation made', () => {
+    const { collection } = testFixtures.collections
+    collection.status = 'underReview'
+
+    const result = ah.stripeCollectionByRole(collection, 'admin')
+    const { handlingEditor = {} } = result
+
+    expect(handlingEditor.name).not.toEqual('Assigned')
+  })
+
+  it('stripeCollection - other user than author should see HE name after recommendation made', () => {
+    const { collection } = testFixtures.collections
+    collection.status = 'revisionRequested'
+
+    const result = ah.stripeCollectionByRole(collection, 'admin')
+    const { handlingEditor = {} } = result
+
+    expect(handlingEditor.name).not.toEqual('Assigned')
+  })
+
+  it('stripeCollection - returns if collection does not have HE', () => {
+    const { collection } = testFixtures.collections
+    delete collection.handlingEditor
+
+    const result = ah.stripeCollectionByRole(collection, 'admin')
+    expect(result.handlingEditor).toBeFalsy()
+  })
+
+  it('stripeFragment - reviewer should not see authors email', () => {
+    const { fragment } = testFixtures.fragments
+    const result = ah.stripeFragmentByRole(fragment, 'reviewer')
+    const { authors = [] } = result
+    expect(authors[0].email).toBeFalsy()
+  })
+  it('stripeFragment - other roles than reviewer should see authors emails', () => {
+    const { fragment } = testFixtures.fragments
+    const result = ah.stripeFragmentByRole(fragment, 'author')
+    const { authors = [] } = result
+
+    expect(authors[0].email).toBeTruthy()
+  })
+
+  it('stripeFragment - reviewer should not see cover letter', () => {
+    const { fragment } = testFixtures.fragments
+    const result = ah.stripeFragmentByRole(fragment, 'reviewer')
+    const { files = {} } = result
+    expect(files.coverLetter).toBeFalsy()
+  })
+  it('stripeFragment - reviewer should not see others reviews', () => {
+    const { fragment } = testFixtures.fragments
+    const result = ah.stripeFragmentByRole(fragment, 'reviewer')
+    const { recommendations } = result
+    expect(recommendations).toEqual([])
+  })
+
+  it('stripeFragment - author should not see private recommendations comments', () => {
+    const { fragment } = testFixtures.fragments
+    fragment.recommendations = [
+      {
+        comments: [
+          {
+            content: 'private',
+            public: false,
+          },
+          {
+            content: 'public',
+            public: true,
+          },
+        ],
+      },
+    ]
+    const result = ah.stripeFragmentByRole(fragment, 'author')
+    const privateComments = get(result, 'recommendations[0].comments')
+    expect(privateComments).toHaveLength(1)
+  })
+})