diff --git a/CHANGELOG b/CHANGELOG
index 7ca450d423cf473b69fe9c61a4af098bbcf13691..ab46ef3b169cd4a0da1285c81a5fb40a85d75f3d 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -17,6 +17,7 @@ v 7.14.0 (unreleased)
   - Add fetch command to the MR page
   - Fix bug causing Bitbucket importer to crash when OAuth application had been removed.
   - Add fetch command to the MR page.
+  - Add ability to manage user email addresses via the API.
 
 v 7.13.2
   - Fix randomly failed spec
diff --git a/doc/api/users.md b/doc/api/users.md
index 5dca77b5c7befe050039f64996129209a5a123a0..9ac55d3f09e72dcceacecedf6c7df9d2aa9e9b64 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -397,6 +397,138 @@ Parameters:
 
 Will return `200 OK` on success, or `404 Not found` if either user or key cannot be found.
 
+## List emails
+
+Get a list of currently authenticated user's emails.
+
+```
+GET /user/emails
+```
+
+```json
+[
+  {
+    "id": 1,
+    "email": "email@example.com"
+  },
+  {
+    "id": 3,
+    "email": "email2@example.com"
+  }
+]
+```
+
+Parameters:
+
+- **none**
+
+## List emails for user
+
+Get a list of a specified user's emails. Available only for admin
+
+```
+GET /users/:uid/emails
+```
+
+Parameters:
+
+- `uid` (required) - id of specified user
+
+## Single SSH key
+
+Get a single key.
+
+```
+GET /user/emails/:id
+```
+
+Parameters:
+
+- `id` (required) - The ID of an SSH key
+
+```json
+{
+  "id": 1,
+  "email": "email@example.com"
+}
+```
+
+## Add email
+
+Creates a new email owned by the currently authenticated user.
+
+```
+POST /user/emails
+```
+
+Parameters:
+
+- `email` (required) - email address
+
+```json
+{
+  "id": 4,
+  "email": "email@example.com"
+}
+```
+
+Will return created key with status `201 Created` on success. If an
+error occurs a `400 Bad Request` is returned with a message explaining the error:
+
+```json
+{
+  "message": {
+    "email": [
+      "has already been taken"
+    ]
+  }
+}
+```
+
+## Add email for user
+
+Create new email owned by specified user. Available only for admin
+
+```
+POST /users/:id/emails
+```
+
+Parameters:
+
+- `id` (required)    - id of specified user
+- `email` (required) - email address
+
+Will return created key with status `201 Created` on success, or `404 Not found` on fail.
+
+## Delete email for current user
+
+Deletes email owned by currently authenticated user.
+This is an idempotent function and calling it on a email that is already deleted
+or not available results in `200 OK`.
+
+```
+DELETE /user/emails/:id
+```
+
+Parameters:
+
+- `id` (required) - email ID
+
+## Delete email for given user
+
+Deletes email owned by a specified user. Available only for admin.
+
+```
+DELETE /users/:uid/emails/:id
+```
+
+Parameters:
+
+- `uid` (required) - id of specified user
+- `id` (required)  - email ID
+
+Will return `200 OK` on success, or `404 Not found` if either user or key cannot be found.
+
 ## Block user
 
 Blocks the specified user.  Available only for admin.
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index ecf1412dee5ab6e51829da488a3570d8bf7bb4be..ce3d09a32cde8cfdec2279c52f0a547c3f2e4c2e 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -31,6 +31,10 @@ module API
       expose :private_token
     end
 
+    class Email < Grape::Entity
+      expose :id, :email
+    end
+
     class Hook < Grape::Entity
       expose :id, :url, :created_at
     end
diff --git a/lib/api/users.rb b/lib/api/users.rb
index c468371d3d44f0f0264b80e7628cd001e4c81f7e..bd8cc9f16a894967084096a6f4a63721c00b4ba3 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -185,6 +185,65 @@ module API
         end
       end
 
+      # Add email to a specified user. Only available to admin users.
+      #
+      # Parameters:
+      # id (required) - The ID of a user
+      # email (required) - Email address
+      # Example Request:
+      # POST /users/:id/emails
+      post ":id/emails" do
+        authenticated_as_admin!
+        required_attributes! [:email]
+
+        user = User.find(params[:id])
+        attrs = attributes_for_keys [:email]
+        email = user.emails.new attrs
+        if email.save
+          NotificationService.new.new_email(email)
+          present email, with: Entities::Email
+        else
+          render_validation_error!(email)
+        end
+      end
+
+      # Get emails of a specified user. Only available to admin users.
+      #
+      # Parameters:
+      # uid (required) - The ID of a user
+      # Example Request:
+      # GET /users/:uid/emails
+      get ':uid/emails' do
+        authenticated_as_admin!
+        user = User.find_by(id: params[:uid])
+        not_found!('User') unless user
+
+        present user.emails, with: Entities::Email
+      end
+
+      # Delete existing email of a specified user. Only available to admin
+      # users.
+      #
+      # Parameters:
+      #   uid (required) - The ID of a user
+      #   id (required) - Email ID
+      # Example Request:
+      #   DELETE /users/:uid/emails/:id
+      delete ':uid/emails/:id' do
+        authenticated_as_admin!
+        user = User.find_by(id: params[:uid])
+        not_found!('User') unless user
+
+        begin
+          email = user.emails.find params[:id]
+          email.destroy
+
+          user.update_secondary_emails!
+        rescue ActiveRecord::RecordNotFound
+          not_found!('Email')
+        end
+      end
+
       # Delete user. Available only for admin
       #
       # Example Request:
@@ -289,6 +348,58 @@ module API
         rescue
         end
       end
+
+      # Get currently authenticated user's emails
+      #
+      # Example Request:
+      #   GET /user/emails
+      get "emails" do
+        present current_user.emails, with: Entities::Email
+      end
+
+      # Get single email owned by currently authenticated user
+      #
+      # Example Request:
+      #   GET /user/emails/:id
+      get "emails/:id" do
+        email = current_user.emails.find params[:id]
+        present email, with: Entities::Email
+      end
+
+      # Add new email to currently authenticated user
+      #
+      # Parameters:
+      #   email (required) - Email address
+      # Example Request:
+      #   POST /user/emails
+      post "emails" do
+        required_attributes! [:email]
+
+        attrs = attributes_for_keys [:email]
+        email = current_user.emails.new attrs
+        if email.save
+          NotificationService.new.new_email(email)
+          present email, with: Entities::Email
+        else
+          render_validation_error!(email)
+        end
+      end
+
+      # Delete existing email of currently authenticated user
+      #
+      # Parameters:
+      #   id (required) - EMail ID
+      # Example Request:
+      #   DELETE /user/emails/:id
+      delete "emails/:id" do
+        begin
+          email = current_user.emails.find params[:id]
+          email.destroy
+
+          current_user.update_secondary_emails!
+        rescue
+        end
+      end
     end
   end
 end
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index c4dd1f76cf2aee870702a4b4d9e5f98593c45f51..7fa6aebca0be6fb7d436cd164430a06613b3d45c 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -6,6 +6,7 @@ describe API::API, api: true  do
   let(:user)  { create(:user) }
   let(:admin) { create(:admin) }
   let(:key)   { create(:key, user: user) }
+  let(:email)   { create(:email, user: user) }
 
   describe "GET /users" do
     context "when unauthenticated" do
@@ -384,6 +385,87 @@ describe API::API, api: true  do
     end
   end
 
+  describe "POST /users/:id/emails" do
+    before { admin }
+
+    it "should not create invalid email" do
+      post api("/users/#{user.id}/emails", admin), { }
+      expect(response.status).to eq(400)
+      expect(json_response['message']).to eq('400 (Bad request) "email" not given')
+    end
+
+    it "should create email" do
+      email_attrs = attributes_for :email
+      expect do
+        post api("/users/#{user.id}/emails", admin), email_attrs
+      end.to change{ user.emails.count }.by(1)
+    end
+  end
+
+  describe 'GET /user/:uid/emails' do
+    before { admin }
+
+    context 'when unauthenticated' do
+      it 'should return authentication error' do
+        get api("/users/#{user.id}/emails")
+        expect(response.status).to eq(401)
+      end
+    end
+
+    context 'when authenticated' do
+      it 'should return 404 for non-existing user' do
+        get api('/users/999999/emails', admin)
+        expect(response.status).to eq(404)
+        expect(json_response['message']).to eq('404 User Not Found')
+      end
+
+      it 'should return array of emails' do
+        user.emails << email
+        user.save
+        get api("/users/#{user.id}/emails", admin)
+        expect(response.status).to eq(200)
+        expect(json_response).to be_an Array
+        expect(json_response.first['email']).to eq(email.email)
+      end
+    end
+  end
+
+  describe 'DELETE /user/:uid/emails/:id' do
+    before { admin }
+
+    context 'when unauthenticated' do
+      it 'should return authentication error' do
+        delete api("/users/#{user.id}/emails/42")
+        expect(response.status).to eq(401)
+      end
+    end
+
+    context 'when authenticated' do
+      it 'should delete existing email' do
+        user.emails << email
+        user.save
+        expect do
+          delete api("/users/#{user.id}/emails/#{email.id}", admin)
+        end.to change { user.emails.count }.by(-1)
+        expect(response.status).to eq(200)
+      end
+
+      it 'should return 404 error if user not found' do
+        user.emails << email
+        user.save
+        delete api("/users/999999/emails/#{email.id}", admin)
+        expect(response.status).to eq(404)
+        expect(json_response['message']).to eq('404 User Not Found')
+      end
+
+      it 'should return 404 error if email not foud' do
+        delete api("/users/#{user.id}/emails/42", admin)
+        expect(response.status).to eq(404)
+        expect(json_response['message']).to eq('404 Email Not Found')
+      end
+    end
+  end
+
   describe "DELETE /users/:id" do
     before { admin }
 
@@ -528,6 +610,95 @@ describe API::API, api: true  do
     end
   end
 
+  describe "GET /user/emails" do
+    context "when unauthenticated" do
+      it "should return authentication error" do
+        get api("/user/emails")
+        expect(response.status).to eq(401)
+      end
+    end
+
+    context "when authenticated" do
+      it "should return array of emails" do
+        user.emails << email
+        user.save
+        get api("/user/emails", user)
+        expect(response.status).to eq(200)
+        expect(json_response).to be_an Array
+        expect(json_response.first["email"]).to eq(email.email)
+      end
+    end
+  end
+
+  describe "GET /user/emails/:id" do
+    it "should return single email" do
+      user.emails << email
+      user.save
+      get api("/user/emails/#{email.id}", user)
+      expect(response.status).to eq(200)
+      expect(json_response["email"]).to eq(email.email)
+    end
+
+    it "should return 404 Not Found within invalid ID" do
+      get api("/user/emails/42", user)
+      expect(response.status).to eq(404)
+      expect(json_response['message']).to eq('404 Not found')
+    end
+
+    it "should return 404 error if admin accesses user's email" do
+      user.emails << email
+      user.save
+      admin
+      get api("/user/emails/#{email.id}", admin)
+      expect(response.status).to eq(404)
+      expect(json_response['message']).to eq('404 Not found')
+    end
+  end
+
+  describe "POST /user/emails" do
+    it "should create email" do
+      email_attrs = attributes_for :email
+      expect do
+        post api("/user/emails", user), email_attrs
+      end.to change{ user.emails.count }.by(1)
+      expect(response.status).to eq(201)
+    end
+
+    it "should return a 401 error if unauthorized" do
+      post api("/user/emails"), email: 'some email'
+      expect(response.status).to eq(401)
+    end
+
+    it "should not create email with invalid email" do
+      post api("/user/emails", user), {}
+      expect(response.status).to eq(400)
+      expect(json_response['message']).to eq('400 (Bad request) "email" not given')
+    end
+  end
+
+  describe "DELETE /user/emails/:id" do
+    it "should delete existed email" do
+      user.emails << email
+      user.save
+      expect do
+        delete api("/user/emails/#{email.id}", user)
+      end.to change{user.emails.count}.by(-1)
+      expect(response.status).to eq(200)
+    end
+
+    it "should return success if email ID not found" do
+      delete api("/user/emails/42", user)
+      expect(response.status).to eq(200)
+    end
+
+    it "should return 401 error if unauthorized" do
+      user.emails << email
+      user.save
+      delete api("/user/emails/#{email.id}")
+      expect(response.status).to eq(401)
+    end
+  end
+
   describe 'PUT /user/:id/block' do
     before { admin }
     it 'should block existing user' do