<h2>Users</h2> <style> #user_table h4 { margin: 1em 0 0 0; } #user_table tr.account_inactive td.address { color: #888; text-decoration: line-through; } #user_table .actions { margin-top: .33em; font-size: 95%; } #user_table .account_inactive .if_active { display: none; } #user_table .account_active .if_inactive { display: none; } #user_table .account_active.if_inactive { display: none; } </style> <h3>Add a mail user</h3> <p>Add an email address to this system. This will create a new login username/password.</p> <form class="form-inline" role="form" onsubmit="return do_add_user(); return false;"> <div class="form-group"> <label class="sr-only" for="adduserEmail">Email address</label> <input type="email" class="form-control" id="adduserEmail" placeholder="Email Address"> </div> <div class="form-group"> <label class="sr-only" for="adduserPassword">Password</label> <input type="password" class="form-control" id="adduserPassword" placeholder="Password"> </div> <div class="form-group"> <select class="form-control" id="adduserPrivs"> <option value="">Normal User</option> <option value="admin">Administrator</option> </select> </div> <button type="submit" class="btn btn-primary">Add User</button> </form> <ul style="margin-top: 1em; padding-left: 1.5em; font-size: 90%;"> <li>Passwords must be at least four characters and may not contain spaces. For best results, <a href="#" onclick="return generate_random_password()">generate a random password</a>.</li> <li>Use <a href="#" onclick="return show_panel('aliases')">aliases</a> to create email addresses that forward to existing accounts.</li> <li>Administrators get access to this control panel.</li> <li>User accounts cannot contain any international (non-ASCII) characters, but <a href="#" onclick="return show_panel('aliases');">aliases</a> can.</li> </ul> <h3>Existing mail users</h3> <table id="user_table" class="table" style="width: auto"> <thead> <tr> <th width="50%">Email Address</th> <th>Actions</th> <th>Mailbox Size</th> </tr> </thead> <tbody> </tbody> </table> <div style="display: none"> <table> <tr id="user-template"> <td class='address'> </td> <td class='actions'> <span class='privs'> </span> <span class="if_active"> <a href="#" onclick="users_set_password(this); return false;" class='setpw' title="Set Password"> set password </a> | </span> <span class='add-privs'> </span> <a href="#" onclick="users_remove(this); return false;" class='if_active' title="Archive Account"> archive account </a> </td> <td class='mailboxsize'> </td> </tr> <tr id="user-extra-template" class="if_inactive"> <td colspan="3" style="border: 0; padding-top: 0"> <div class='restore_info' style='color: #888; font-size: 90%'>To restore account, create a new account with this email address. Or to permanently delete the mailbox, delete the directory <tt></tt> on the machine.</div> </td> </tr> </table> </div> <h3>Mail user API (advanced)</h3> <p>Use your box’s mail user API to add/change/remove users from the command-line or custom services you build.</p> <p>Usage:</p> <pre>curl -X <b>VERB</b> [-d "<b>parameters</b>"] --user {email}:{password} https://{{hostname}}/admin/mail/users[<b>action</b>]</pre> <p>Brackets denote an optional argument. Please note that the POST body <code>parameters</code> must be URL-encoded.</p> <p>The email and password given to the <code>--user</code> option must be an administrative user on this system.</p> <h4 style="margin-bottom: 0">Verbs</h4> <table class="table" style="margin-top: .5em"> <thead><th>Verb</th> <th>Action</th><th></th></thead> <tr><td>GET</td><td><i>(none)</i></td> <td>Returns a list of existing mail users. Adding <code>?format=json</code> to the URL will give JSON-encoded results.</td></tr> <tr><td>POST</td><td>/add</td> <td>Adds a new mail user. Required POST-body parameters are <code>email</code> and <code>password</code>.</td></tr> <tr><td>POST</td><td>/remove</td> <td>Removes a mail user. Required POST-by parameter is <code>email</code>.</td></tr> <tr><td>POST</td><td>/privileges/add</td> <td>Used to make a mail user an admin. Required POST-body parameters are <code>email</code> and <code>privilege=admin</code>.</td></tr> <tr><td>POST</td><td>/privileges/remove</td> <td>Used to remove the admin privilege from a mail user. Required POST-body parameter is <code>email</code>.</td></tr> </table> <h4>Examples:</h4> <p>Try these examples. For simplicity the examples omit the <code>--user me@mydomain.com:yourpassword</code> command line argument which you must fill in with your administrative email address and password.</p> <pre># Gives a JSON-encoded list of all mail users curl -X GET https://{{hostname}}/admin/mail/users?format=json # Adds a new email user curl -X POST -d "email=new_user@mydomail.com" -d "password=s3curE_pa5Sw0rD" https://{{hostname}}/admin/mail/users/add # Removes a email user curl -X POST -d "email=new_user@mydomail.com" https://{{hostname}}/admin/mail/users/remove # Adds admin privilege to an email user curl -X POST -d "email=new_user@mydomail.com" -d "privilege=admin" https://{{hostname}}/admin/mail/users/privileges/add # Removes admin privilege from an email user curl -X POST -d "email=new_user@mydomail.com" https://{{hostname}}/admin/mail/users/privileges/remove </pre> <script> function show_users() { $('#user_table tbody').html("<tr><td colspan='2' class='text-muted'>Loading...</td></tr>") api( "/mail/users", "GET", { format: 'json' }, function(r) { $('#user_table tbody').html(""); for (var i = 0; i < r.length; i++) { var hdr = $("<tr><td colspan='3'><h4/></td></tr>"); hdr.find('h4').text(r[i].domain); $('#user_table tbody').append(hdr); for (var k = 0; k < r[i].users.length; k++) { var user = r[i].users[k]; var n = $("#user-template").clone(); var n2 = $("#user-extra-template").clone(); n.attr('id', ''); n2.attr('id', ''); $('#user_table tbody').append(n); $('#user_table tbody').append(n2); n.addClass("account_" + user.status); n2.addClass("account_" + user.status); n.attr('data-email', user.email); n.find('.address').text(user.email) n.find('.mailboxsize').text(nice_size(user.mailbox_size)) n2.find('.restore_info tt').text(user.mailbox); if (user.status == 'inactive') continue; var add_privs = ["admin"]; for (var j = 0; j < user.privileges.length; j++) { var p = $("<span><b><span class='name'></span></b> (<a href='#' onclick='mod_priv(this, \"remove\"); return false;' title='Remove Privilege'>remove privilege</a>) |</span>"); p.find('span.name').text(user.privileges[j]); n.find('.privs').append(p); if (add_privs.indexOf(user.privileges[j]) >= 0) add_privs.splice(add_privs.indexOf(user.privileges[j]), 1); } for (var j = 0; j < add_privs.length; j++) { var p = $("<span><a href='#' onclick='mod_priv(this, \"add\"); return false;' title='Add Privilege'>make <span class='name'></span></a> | </span>"); p.find('span.name').text(add_privs[j]); n.find('.add-privs').append(p); } } } }) } function do_add_user() { var email = $("#adduserEmail").val(); var pw = $("#adduserPassword").val(); var privs = $("#adduserPrivs").val(); api( "/mail/users/add", "POST", { email: email, password: pw, privileges: privs }, function(r) { // Responses are multiple lines of pre-formatted text. show_modal_error("Add User", $("<pre/>").text(r)); show_users() }, function(r) { show_modal_error("Add User", r); }); return false; } function users_set_password(elem) { var email = $(elem).parents('tr').attr('data-email'); var yourpw = ""; if (api_credentials != null && email == api_credentials[0]) yourpw = "<p class='text-danger'>If you change your own password, you will be logged out of this control panel and will need to log in again.</p>"; show_modal_confirm( "Set Password", $("<p>Set a new password for <b>" + email + "</b>?</p> <p><label for='users_set_password_pw' style='display: block; font-weight: normal'>New Password:</label><input type='password' id='users_set_password_pw'></p><p><small>Passwords must be at least four characters and may not contain spaces.</small>" + yourpw + "</p>"), "Set Password", function() { api( "/mail/users/password", "POST", { email: email, password: $('#users_set_password_pw').val() }, function(r) { // Responses are multiple lines of pre-formatted text. show_modal_error("Set Password", $("<pre/>").text(r)); }, function(r) { show_modal_error("Set Password", r); }); }); } function users_remove(elem) { var email = $(elem).parents('tr').attr('data-email'); // can't remove yourself if (api_credentials != null && email == api_credentials[0]) { show_modal_error("Archive User", "You cannot archive your own account."); return; } show_modal_confirm( "Archive User", $("<p>Are you sure you want to archive <b>" + email + "</b>?</p> <p>The user's mailboxes will not be deleted (you can do that later), but the user will no longer be able to log into any services on this machine.</p>"), "Archive", function() { api( "/mail/users/remove", "POST", { email: email }, function(r) { // Responses are multiple lines of pre-formatted text. show_modal_error("Remove User", $("<pre/>").text(r)); show_users(); }, function(r) { show_modal_error("Remove User", r); }); }); } function mod_priv(elem, add_remove) { var email = $(elem).parents('tr').attr('data-email'); var priv = $(elem).parents('td').find('.name').text(); // can't remove your own admin access if (priv == "admin" && add_remove == "remove" && api_credentials != null && email == api_credentials[0]) { show_modal_error("Modify Privileges", "You cannot remove the admin privilege from yourself."); return; } var add_remove1 = add_remove.charAt(0).toUpperCase() + add_remove.substring(1); show_modal_confirm( "Modify Privileges", $("<p>Are you sure you want to " + add_remove + " the " + priv + " privilege for <b>" + email + "</b>?</p>"), add_remove1, function() { api( "/mail/users/privileges/" + add_remove, "POST", { email: email, privilege: priv }, function(r) { show_users(); }); }); } function generate_random_password() { var pw = ""; var charset = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz23456789"; // confusable characters skipped for (var i = 0; i < 10; i++) pw += charset.charAt(Math.floor(Math.random() * charset.length)); show_modal_error("Random Password", "<p>Here, try this:</p> <p><code style='font-size: 110%'>" + pw + "</code></pr"); return false; // cancel click } </script>