diff --git a/message/amd/build/message_preferences.min.js b/message/amd/build/message_preferences.min.js
new file mode 100644
index 00000000000..54bf9178e48
--- /dev/null
+++ b/message/amd/build/message_preferences.min.js
@@ -0,0 +1 @@
+define(["jquery","core/ajax","core/notification","core_message/message_notification_preference","core/custom_interaction_events"],function(a,b,c,d,e){var f={PREFERENCE:"[data-state]",PREFERENCES_CONTAINER:'[data-region="preferences-container"]',CONTACTABLE_PRIVACY_CONTAINER:'[data-region="privacy-setting-container"]'},g=function(b){this.root=a(b),this.userId=this.root.find(f.PREFERENCES_CONTAINER).attr("data-user-id"),this.registerEventListeners()};return g.prototype.preferencesDisabled=function(){return this.root.find(f.PREFERENCES_CONTAINER).hasClass("disabled")},g.prototype.saveContactablePrivacySetting=function(){var d=this.root.find(f.CONTACTABLE_PRIVACY_CONTAINER),e=a("input[type='radio']:checked").val();if(d.hasClass("loading"))return a.Deferred().resolve();d.addClass("loading");var g={methodname:"core_user_update_user_preferences",args:{userid:this.userId,preferences:[{type:d.attr("data-preference-key"),value:e}]}};return b.call([g])[0].fail(c.exception).always(function(){d.removeClass("loading")})},g.prototype.registerEventListeners=function(){e.define(this.root,[e.events.activate]),this.root.on("change",function(b){if("message_blocknoncontacts"==b.target.name)this.saveContactablePrivacySetting();else if(!this.preferencesDisabled()){var c=a(b.target).closest(f.PREFERENCES_CONTAINER),e=a(b.target).closest(f.PREFERENCE),g=new d(c,this.userId);e.addClass("loading"),g.save().always(function(){e.removeClass("loading")})}}.bind(this))},g});
\ No newline at end of file
diff --git a/message/amd/src/message_preferences.js b/message/amd/src/message_preferences.js
new file mode 100644
index 00000000000..c5944b62ce2
--- /dev/null
+++ b/message/amd/src/message_preferences.js
@@ -0,0 +1,125 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see .
+
+/**
+ * Controls the message preference page.
+ *
+ * @module core_message/message_preferences
+ * @class message_preferences
+ * @package message
+ * @copyright 2016 Ryan Wyllie
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+define(['jquery', 'core/ajax', 'core/notification',
+ 'core_message/message_notification_preference', 'core/custom_interaction_events'],
+ function($, Ajax, Notification, MessageNotificationPreference, CustomEvents) {
+
+ var SELECTORS = {
+ PREFERENCE: '[data-state]',
+ PREFERENCES_CONTAINER: '[data-region="preferences-container"]',
+ CONTACTABLE_PRIVACY_CONTAINER: '[data-region="privacy-setting-container"]',
+ };
+
+ /**
+ * Constructor for the MessagePreferences.
+ *
+ * @param {object} element The root element for the message preferences
+ */
+ var MessagePreferences = function(element) {
+ this.root = $(element);
+ this.userId = this.root.find(SELECTORS.PREFERENCES_CONTAINER).attr('data-user-id');
+
+ this.registerEventListeners();
+ };
+
+ /**
+ * Check if the preferences have been disabled on this page.
+ *
+ * @method preferencesDisabled
+ * @return {bool}
+ */
+ MessagePreferences.prototype.preferencesDisabled = function() {
+ return this.root.find(SELECTORS.PREFERENCES_CONTAINER).hasClass('disabled');
+ };
+
+ /**
+ * Update the contactable privacy user preference in the DOM and
+ * send a request to update on the server.
+ *
+ * @return {Promise}
+ * @method saveContactablePrivacySetting
+ */
+ MessagePreferences.prototype.saveContactablePrivacySetting = function() {
+ var container = this.root.find(SELECTORS.CONTACTABLE_PRIVACY_CONTAINER);
+ var value = $("input[type='radio']:checked").val();
+
+ if (container.hasClass('loading')) {
+ return $.Deferred().resolve();
+ }
+
+ container.addClass('loading');
+
+ var request = {
+ methodname: 'core_user_update_user_preferences',
+ args: {
+ userid: this.userId,
+ preferences: [
+ {
+ type: container.attr('data-preference-key'),
+ value: value,
+ }
+ ]
+ }
+ };
+
+ return Ajax.call([request])[0]
+ .fail(Notification.exception)
+ .always(function() {
+ container.removeClass('loading');
+ });
+ };
+
+ /**
+ * Create all of the event listeners for the message preferences page.
+ *
+ * @method registerEventListeners
+ */
+ MessagePreferences.prototype.registerEventListeners = function() {
+ CustomEvents.define(this.root, [
+ CustomEvents.events.activate
+ ]);
+
+ this.root.on('change', function(e) {
+ // Add listener for privacy setting radio buttons change.
+ if (e.target.name == 'message_blocknoncontacts') {
+ this.saveContactablePrivacySetting();
+ } else {
+ // Add listener for processor preferences.
+ if (!this.preferencesDisabled()) {
+ var preferencesContainer = $(e.target).closest(SELECTORS.PREFERENCES_CONTAINER);
+ var preferenceElement = $(e.target).closest(SELECTORS.PREFERENCE);
+ var messagePreference = new MessageNotificationPreference(preferencesContainer, this.userId);
+
+ preferenceElement.addClass('loading');
+ messagePreference.save().always(function() {
+ preferenceElement.removeClass('loading');
+ });
+ }
+ }
+ }.bind(this));
+ };
+
+ return MessagePreferences;
+});
diff --git a/message/templates/message_preferences.mustache b/message/templates/message_preferences.mustache
new file mode 100644
index 00000000000..ebe1c40840c
--- /dev/null
+++ b/message/templates/message_preferences.mustache
@@ -0,0 +1,119 @@
+{{!
+ This file is part of Moodle - http://moodle.org/
+
+ Moodle is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Moodle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Moodle. If not, see .
+}}
+{{!
+ @template core_message/message_preferences
+
+ The message preferences page
+
+ Classes required for JS:
+ * None
+
+ Data attibutes required for JS:
+ * All data attributes are required
+
+ Context variables required for this template:
+ * userid The logged in user id
+ * disableall If the user has disabled notifications
+ * components The list of notification components
+ * privacychoices The choice options for the contactable privacy setting
+
+ Example context (json):
+ {
+ "userid": 1,
+ "disableall": 0,
+ "components": [
+ {
+ "notifications": [
+ {
+ "displayname": "Notices about minor problems",
+ "preferencekey": "message_provider_moodle_notices",
+ "onlinehelphtml": "
+{{#js}}
+require(['jquery', 'core_message/message_preferences'],
+ function($, MessagePreferences) {
+
+ new MessagePreferences($('[data-region="preferences-page-container"]'));
+});
+{{/js}}
diff --git a/message/templates/message_preferences_component.mustache b/message/templates/message_preferences_component.mustache
new file mode 100644
index 00000000000..aeac0261a2b
--- /dev/null
+++ b/message/templates/message_preferences_component.mustache
@@ -0,0 +1,84 @@
+{{!
+ This file is part of Moodle - http://moodle.org/
+
+ Moodle is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Moodle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Moodle. If not, see .
+}}
+{{!
+ @template core_message/message_preferences_component
+
+ The message preferences page
+
+ Classes required for JS:
+ * None
+
+ Data attibutes required for JS:
+ * All data attributes are required
+
+ Context variables required for this template:
+ * notifications The list of notifications
+
+ Example context (json):
+ {
+ "notifications": [
+ {
+ "displayname": "Notices about minor problems",
+ "preferencekey": "message_provider_moodle_notices",
+ "onlinehelphtml": "
+ {{#processors}}
+ {{> message/message_preferences_notification_processor }}
+ {{/processors}}
+{{/notifications}}
diff --git a/message/templates/message_preferences_notification_processor.mustache b/message/templates/message_preferences_notification_processor.mustache
new file mode 100644
index 00000000000..43c38eff4e4
--- /dev/null
+++ b/message/templates/message_preferences_notification_processor.mustache
@@ -0,0 +1,127 @@
+{{!
+ This file is part of Moodle - http://moodle.org/
+
+ Moodle is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Moodle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Moodle. If not, see .
+}}
+{{!
+ @template core_message/message_preferences_notification_processor
+
+ The message preferences page
+
+ Classes required for JS:
+ * None
+
+ Data attibutes required for JS:
+ * All data attributes are required
+
+ Context variables required for this template:
+ * displayname The display name of the processor
+ * name The name of the processor
+ * locked Whether the processor is locked
+ * loggedin The logged in settings
+ * loggedoff The logged off settings
+
+ Example context (json):
+ {
+ "displayname": "Notices about minor problems",
+ "preferencekey": "message_provider_moodle_notices",
+ "processors": [
+ {
+ "displayname": "Popup notification",
+ "name": "popup",
+ "locked": 0,
+ "userconfigured": 1,
+ "loggedin": {
+ "name": "loggedin",
+ "displayname": "When I'm logged in",
+ "checked": 0,
+ "disableall": 0
+ },
+ "loggedoff": {
+ "name": "loggedoff",
+ "displayname": "When I'm offline",
+ "checked": 0,
+ "disableall": 0
+ }
+ }
+ ]
+ }
+}}
+
+
{{displayname}}
+
+ {{#locked}}
+
{{lockedmessage}}
+ {{/locked}}
+ {{^locked}}
+
{{#str}} disabled, question {{/str}}
+
+ {{/locked}}
+
+
diff --git a/message/tests/behat/message_preferences.feature b/message/tests/behat/message_preferences.feature
new file mode 100644
index 00000000000..4aeac16e87f
--- /dev/null
+++ b/message/tests/behat/message_preferences.feature
@@ -0,0 +1,30 @@
+@core @core_message
+Feature: To be able to see and save user message preferences as admin
+ As an admin
+ I need to be able to view and edit message preferences for other users
+
+ Background:
+ Given the following "users" exist:
+ | username | firstname | lastname | email |
+ | student1 | Student | 1 | student1@emample.com |
+ And the following "user preferences" exist:
+ | user | preference | value |
+ | student1 | message_provider_moodle_instantmessage_loggedin | none |
+ | student1 | message_provider_moodle_instantmessage_loggedoff | email |
+
+ @javascript
+ Scenario: As an admin I can view and edit message preferences for a user
+ Given I log in as "admin"
+ And I navigate to "Messaging > Notification settings" in site administration
+ And I set the field "email" to "1"
+ And I press "Save changes"
+ And I navigate to "Users > Accounts > Browse list of users" in site administration
+ And I click on "Student 1" "link" in the "Student 1" "table_row"
+ And I click on "Preferences" "link" in the "#region-main-box" "css_element"
+ And I click on "Message preferences" "link" in the "#region-main-box" "css_element"
+ And I click on "//label[@data-state='loggedoff']" "xpath_element"
+ And I log out
+ And I log in as "student1"
+ And I follow "Preferences" in the user menu
+ And I click on "Message preferences" "link"
+ And the field "Email" matches value "0"
\ No newline at end of file