- Example
- Install
- Callback
- Errors
- Zimbra Resources
- Common Functions
- Server Operations
- Batch Request Functions
- Creating Resources
- Modify Resources
- Remove Resources
- Accounts
- Cos
- Domains
- Distribution Lists
- Contributing
First, instantiate the wrapper.
var client = new ZimbraAdminApi({
'url': 'http://zimbra.zboxapp.dev:8000/service/admin/soap',
'user': 'admin@zboxapp.dev',
'password':'12345678'
});
var callback = function(err, data) {
if (err) return console.log(err);
console.log(data);
};
client.getAllDomains(callback);
ZimbraAdminApi.version();
// "version"
You must use the correct url
.
var client = new ZimbraAdminApi({
'url': 'http://zimbra.zboxapp.dev:8000/service/soap',
'user': 'normal_user@zboxapp.dev',
'password':'12345678',
'isAdmin': false
});
$ npm install --save zimbra-admin-api-js
You have to pass a callback
to all the functions, that receives to params:
error
, if anydata
, if any
For this documentations callback
will always be:
function(err, data) {
if (err) return console.log(err);
console.log(data);
};
If Zimbra returns an Error, the library returns an Error
Object with the Zimbra Error
information. For example, if you look for a non existing Domain
:
client.getDomain('example.com', callback);
// Error: {status: 500, title: "Internal Server Error", extra: Object}
// Error.extra: {
// code: "account.NO_SUCH_DOMAIN",
// reason: "no such domain: example.com"
// }
Zimbra Resources are the things you can manage, like:
Accounts
, the email users,Domains
,Distribution Lists
,CoS
, Class of servicesServers
, Zimbra servers
This are similar functions that you can call for all the Resources
, so we grouped here
for brevity:
You can use the resource name
or zimbraId
:
client.getAccount('account@domain.com', callback);
// Account {name: "admin@domain.com", id: "eda93f93-ba26-4344-8ae0-1d03964b612a", attrs: Object}
client.getAccount('eda93f93-ba26-4344-8ae0-1d03964b612a', callback);
// Account {name: "admin@domain.com", id: "eda93f93-ba26-4344-8ae0-1d03964b612a", attrs: Object}
client.getDomain('domain.com', callback);
// Domain {name: "domain.com", id: "cc0fd82b-7833-4de2-8954-88eb97fb81e9", attrs: Object}
client.getDistributionList('list@domain.com', callback);
// DistributionList {name: "list@domain.com", id: "747972ab-a410-4f17-8d5e-db7be21d75e9", attrs: Object, members: Array[4]}
A successful response will always return a Object
named after the Resource
your are requesting.
You have the following functions:
getAllAccounts(query_object, callback)
,getAllDomains(query_object, callback)
,getAllDistributionLists(query_object, callback)
,
query_object
is an optional Object
that accept the following attributes:
query
: An LDAP query or null for everything,maxResults
: Maximum results that the backend will attempt to fetch from the directory before returning anaccount.TOO_MANY_SEARCH_RESULTS
error.,limit
: the maximum number of accounts to return ,offset
: The starting offset (0, 25, etc),domain
: The domain name to limit the search to,sortBy
: Name of attribute to sort on. Default is the account name.,sortAscending
: Whether to sort in ascending order. Default is 1 (true)countOnly
: Whether response should be count only. Default is 0 (false),attrs
: Comma separated list of attributes to ask for
If you need to get the result as an Object with the resource id
or name
as the Key
of the object you need to initialize the Api like this:
var client = new ZimbraAdminApi({
'url': 'http://zimbra.zboxapp.dev:8000/service/admin/soap',
'user': 'admin@zboxapp.dev',
'password':'12345678',
'arrayAsObject': true,
'arrayAsObjectKey': 'name' // By default is 'id';
});
var callback = function(err, data) {
if (err) return console.log(err);
console.log(data);
};
client.getAllDomains(callback);
// Object {total: 261, more: false, domain: Object} <== Object!!
client.getAllAccounts(callback);
// Object {total: 261, more: false, account: Array[261]}
The Result Object has the following information:
total
: The total quantity of resources that you request can return,account
, An array with all theAccounts
objects,more
:true
if there are more results that.
This is useful if you are doing pagination.
var query_object = { limit: 10, offset: 2 }
client.getAllAccounts(callback);
// Object {total: 261, more: true, account: Array[10]}
var query_object = { domain: 'example.com' }
client.getAllDistributionLists(query_object, callback);
// Object {total: 6, more: false, dl: Array[6]}
var query_object = { query: 'mail=*basic*' }
client.getAllAccounts(query_object, callback);
// Object {total: 29, more: false, account: Array[29]}
Do a backup <account>
elements are required when method=full
and server is running in standard backup mode. If server is running in auto-grouped backup mode, omit the account list in full backup request to trigger auto-grouped backup. If account list is specified, only those accounts will be backed up.
Full documentation: https://files.zimbra.com/docs/soap_api/8.7.0/api-reference/zimbraAdmin/Backup.html
The first param is the Mailbox Server
. You need direct access to the 7071
port on this server.
const backupRequest = {blobs: 'exclude', secondaryBlobs: 'exclude', searchIndex: 'exclude'};
const accounts = ['account2@example.com', 'account1@example.com'];
api.backup("localhost", backupRequest, null, accounts, callback);
// {label: "full-20160830.222823.315"}
Get All Volumes from the server. This link has full documentation
The server
param is the hostname
or ip address
of the Mailbox Server. You need direct access to the 7071
port on this server.
api.getAllVolumes("localhost", callback);
// { message1:
// { id: 1,
// name: 'message1',
// type: 1,
// compressBlobs: false,
// compressionThreshold: 4096,
// mgbits: 8,
// mbits: 12,
// fgbits: 8,
// fbits: 12,
// rootpath: '/opt/zimbra/store',
// isCurrent: true },
// index1:
// { id: 2,
// name: 'index1',
// type: 10,
// compressBlobs: false,
// compressionThreshold: 4096,
// mgbits: 8,
// mbits: 12,
// fgbits: 8,
// fbits: 12,
// rootpath: '/opt/zimbra/index',
// isCurrent: true },
// }
Moves blobs between volumes. Unlike HsmRequest
, this request is synchronous, and reads parameters from the request attributes instead of zimbraHsmPolicy
.
Takes the following parameters:
server
, IP or hostname of the mailbox server. You need direct access to the7071
port on this server,request_object
, Object with attributes to make the request.
The request_object
has the following attributes:
types
: Comma separated list of search types. Legal values are:conversation|message|contact|appointment|task|wiki|document
,sourceVolumeIds
: A comma separated list of source volume IDsdestVolumeId
: Destination volume IDmaxBytes
: Limit for the total number of bytes of data to move. Blob move will abort if this threshold is exceeded.query
: An optional query to move only Blobs that match this query. For query syntax check this documentation.
const request_object = {
types: 'all', sourceVolumeIds: '1',
destVolumeId: '3', maxBytes: 100000
};
api.moveBlobs("192.168.0.272", request_object, callback);
// {
// numBlobsMoved: 0,
// numBytesMoved: 0,
// totalMailboxes: 376
// }
With BatchRequest
you can ask Zimbra to run multiple requests in just one call, and get
the result in just one answer.
Every function here works for BatchRequest
if you do not pass a callback
. For example:
var allAccounts = client.getAllAccounts();
var allDomains = client.getAllDomains();
client.makeBatchRequest([allAccounts, allDomains], callback);
// Object {SearchDirectoryResponse: Array[2], _jsns: "urn:zimbra"}
// SearchDirectoryResponse[0].account, SearchDirectoryResponse[1].domain
client.makeBatchRequest([allAccounts, allDomains], callback, {onError: 'continue'});
// By default is {onError: 'stop'}
Pass an array of domains ids or names and you get back an array of countAccounts
responses
objects. The response arrays has the same order of the request array:
var domains = ['zboxapp.com', 'example.com', 'zboxnow.com'];
client.batchCountAccounts(domains, callback);
// [Object, Object];
The methods are:
createAccount('email_address', password, zimbra_attributes, callback)
,createDomain('domain_name', zimbra_attributes, callback)
,createDistributionList('email_address', zimbra_attributes, callback)
Always have to pass an email_address
and a password
:
var zimbra_attributes = {};
client.createAccount('user1@example.com', 'SuP3rS3cur3P4ss', zimbra_attributes, callback);
// Account {name: "user1@example.com", id: "1919c856-08cc-43c9-b927-0c4cf88f50c7", attrs: Object}
We are making zimbra_attributes
and empty object, because we are not passing any attributes.
If everything goes OK you get the created Object as a result.
Check the space between user
and 1@example.com
var zimbra_attributes = {};
client.createAccount('user 1@example.com', 'SuP3rS3cur3P4ss', zimbra_attributes, callback);
// Error {status: 500, title: "Internal Server Error", extra: Object}
// Error.extra {
// code: "service.INVALID_REQUEST",
// reason: "invalid request: invalid email address"
// }
You get an Error
Object with the reason of the failure.
zimbra_attributes
must be an Object
, that can be empty, that should have valid Zimbra attributes
for the Resource
being created.
In this example we are creating an account with the following attributes:
- First Name (
givenName
), - Last Name (
sn
), and - A Mail Quota of
50GB
(zimbraMailQuota
)
var zimbra_attributes = {
givenName: 'John',
sn: 'Smith',
zimbraMailQuota: 53687091200
}
client.createAccount('user@example.com', 'SuP3rS3cur3P4ss', zimbra_attributes, callback);
// Account {name: "user@example.com", id: "1919c856-08cc-43c9-b927-0c4cf88f50c7", attrs: Object}
For updating resources you have to use the ZimbraId
modifyAccount(zimbra_id, attributes, callback)
,modifyDomain(zimbra_id, attributes, callback)
,modifyDistributionList(zimbra_id, attributes, callback)
For example:
// Attributes to modify
var zimbra_attributes = {
givenName: 'Tom',
sn: 'Hanks'
}
// user@example.com
var zimbraId = "1919c856-08cc-43c9-b927-0c4cf88f50c7";
client.modifyAccount(zimbraId, zimbra_attributes, callback);
// Account {name: "user@example.com", id: "1919c856-08cc-43c9-b927-0c4cf88f50c7", attrs: Object}
// attrs.sn = 'Hanks'
// attrs.givenName = 'Tom'
For deleting resources you have to use the ZimbraId
removeAccount(zimbra_id, callback)
,removeDomain(zimbra_id, callback)
,removeDistributionList(zimbra_id, callback)
For example:
// user@example.com
var zimbraId = "1919c856-08cc-43c9-b927-0c4cf88f50c7";
client.removeAccount(zimbraId, callback);
- If everything goes OK you receive nothing as result.
- You can't delete a
Domain
that is not empty. If it has anyAccount
orDistributionList
, You have to delete those first.
account.setPassword(password, callback);
// {} if OK
// Error if not OK
Only Zimbra Network Edition
You must pass a COS Name
or CosID
as firt params
account.enableArchiving('default', callback);
// Account {}
// account.archiveEnabled === true;
account.disableArchiving(callback);
// Account {}
// account.archiveEnabled === false;
Get distribution lists an account is a member of.
client.getAccountMembership(account, callback);
// [DistributionList, DistributionList, ...]
// Or as a method of the account
account.getAccountMembership(callback);
// [DistributionList, DistributionList, ...]
account.getMailbox(callback);
// Object { mbxid: Mailbox ID, size: Quota Used}
//
account.getMailboxSize(callback);
// Returns a Integer represeting Bytes
//
account.rename('new_name@example.com', callback);
// account Object
The alias
must be an email with Domain
in Zimbra.
account.addAccountAlias(alias, callback);
// Empty {} if everything goes Ok
account.removeAccountAlias(alias, callback);
// Empty {} if everything goes Ok
This return an URL PATH
to access the account Webmail as an administrator.
The first parameter is the lifetime
of the Token in seconds.
client.getAccountViewMailPath(account.name, 3600, callback);
// OR
account.viewMailPath(3600, callback);
// /service/preauth?authtoken=0_8c671f3146....&isredirect=1&adminPreAuth=1
The account only has the Id of the Cos, zimbraCOSId
, but not the name. To get the name you call zimbraCosName
on the Account:
// account is a Account, you got it from client.getAccount....
account.cosName(callback);
// professional
// An account without Cos
no_cos_account.cosName(callback);
// null
This are functions especifics to Cos
.
client.getAllCos(callback);
To create a Cos
//Simple, without attributes
var attributes = {};
client.createCos("cos_name", attributes, callback);
// With attributes
var attributes = {'zimbraFeatureContactsEnabled' : 'FALSE'};
client.createCos("cos_name", attributes, callback)
To delete a Cos
client.deleteCos("cos_Id", callback)
client.getCos(name|id, callback);
var attributes = {'zimbraDumpsterEnabled' : 'TRUE'};
client.modifyCos("cos_Id", attributes, callback);
var newName = "basicv2"
client.renameCos("cos_Id", newName, callback);
To copy a Cos with other name
var newCos = "Pro2";
client.copyCos(nameCos|idCos, newCos, callback);
This are functions especifics to Domains
.
These are properties
, not functions.
isAliasDomain
, return if a Domain is an Alias Domain.masterDomainName
, return the name of the master domain.
domain.isAliasDomain
// true || false
domain.masterDomainName
// example.com
Count number of accounts by CoS
in a domain.
client.countAccounts('example.com', callback);
// Object { premium: Object, professional: Object}
// premium: {
// id: _COSId_,
// used: 50
// }
}
If you have a Domain
you can call countAccounts(callback)
on it and it will returns the Limit of Accounts for the Domain
:
// domain is a Domain, you got it from client.getDomain....
domain.countAccounts(callback);
// Object { premium: Object, professional: Object}
// premium: {
// id: _COSId_,
// used: 50,
// limit: 28
// }
}
If the Domain
is empty, no 'Accounts', the result will be a {}
.
client.checkDomainMxRecord(domain.name, callback);
// OR
domain.checkMxRecord(callback);
// Object {entry: "5 mailcleaner.zboxapp.com.", code: "Failed",
// message: "Domain is configured to use SMTP host: zimbra.zboxapp.dev. None of the MX records match this name."}
To add or remove a Domain Admin
you must use the account.id
.
You should also specify the coses
the Domain Admin
can assign to the accounts of his domains.
const coses = ['default', 'test', 'professional'];
api.addDomainAdmin(domain.name, account.id, coses, callback);
// OR
domain.addAdmin(account.id, coses, callback);
// {} if Success
api.removeDomainAdmin(domain.name, account.id, coses, callback);
// OR
domain.removeAdmin(account.id, coses, callback);
// {} if Success
Return an Array of the Domain Admins Accounts
.
// domain is a Domain, you got it from client.getDomain....
api.getDomainAdmins(domain.name, callback);
// OR
domain.getAdmins(callback);
// [Account, Account]
Return an Array of the Domain DistributionList
s.
// domain is a Domain, you got it from client.getDomain....
domain.getAllDistributionLists(callback);
// [DistributionList, DistributionList]
dl.rename('new_name@example.com', callback);
// dl Object
dl.addMembers('new_member@example.com', callback);
// {} if Success
dl.addMembers(['1@example.com', '2@example.com'], callback);
dl.removeMembers('new_member@example.com', callback);
// {} if Success
dl.removeMembers(['1@example.com', '2@example.com'], callback);
// Return Error if any of the emails isn't a member
client.addDistributionListOwner(dl.name, 'new_member@example.com', callback);
// OR
dl.addOwner('new_member@example.com', callback);
// {} if Success
client.removeDistributionListOwner(dl.name, 'new_member@example.com', callback);
// OR
dl.removeOwner('new_member@example.com', callback);
// {} if Success
Owners are the Zimbra emails addresses that are allowed to send emails to the DL
.
If a DL
has at least one Owener
is a Private DL.
client.getDistributionListOwners(dl.name, callback);
// OR
dl.getOwners(callback);
// Array of Objects
// {name: 'email_address', id: 'ZimbraId', type: 'usr|grp'}
To set alias at DL
.
client.addDistributionListAlias(dl.id, alias, callback);
To delete alias of DL
.
api.removeDistributionListAlias(dl.id, alias, callback);
- Fork the repo on GitHub
- Clone the project to your own machine
- Commit changes to your own branch
- Push your work back up to your fork
- Submit a Pull request so that we can review your changes
NOTE: Be sure to merge the latest from "upstream" before making a pull request!
This repo include a Vagrantfile that setups a VM ready for development. This VM provision a Zimbra server with all the resources needed. So you need to install Vagrant if you haven't.
Also you need to install Ansible because we use it to provision the VM.
Once you have everything in place just run:
$ vagrant up
$ vagrant provision
And wait for it to finish.
You must write test for every feature that you add, otherwise we wont accept your Pull Request.
We are using Mocha and Chai for testing. To run the test just execute:
$ npm run test
Also we have Travis-CI that run the test for every Pull Request.