Zimlet cookbook based on JavaScript API

Revision as of 21:53, 1 April 2009 by Rrao (talk | contribs) (How to add additional functionality to an existing button)

Zimlet (ZmZimletBase object)


How to get access to an email("ZmMailMsg" object) when its drag-dropped onto Zimlet's panel Item

First off we need to allow message(ZmMailMsg) or conversation(ZmConv) to be dragged onto Zimlet Panel Item.

  <zimletPanelItem label="Zimlet Name" icon="Zimlet-panelIcon">
		<dragSource type="ZmConv" />
		<dragSource type="ZmMailMsg" />

Then, within the Zimlet's Javascript file, we need to override 'doDrop' function.

com_zimbra_coloredemails.prototype.doDrop =
function(zmObject) {


The email dropped(zmObject) can be either a conversation or a single email. This zmObject internally has an object called 'srcObj' (source-object) and contains the real or actual Zimbra Object that was dropped. Once we get access to this, we can access all the properties and even functions.

com_zimbra_coloredemails.prototype.doDrop =
function(zmObject) {
     var msgObj = zmObject.srcObj;//get access to source-object

    //if its a conversation i.e. "ZmConv" object, get the first loaded message "ZmMailMsg" object within that.
    if (zmObject.type == "CONV") {
      msgObj  = zmObject.getFirstHotMsg();


At this point we have a single message "ZmMailMsg" object and we can access all its properties.

Get mail subject

  var subject = msgObj.subject; //where msgObj is of type "ZmMailMsg"

Get all email address

var emailsArray =  msgObj.getEmails(); //where msgObj is of type "ZmMailMsg"

Get email addresses only in CC

var ccemails = [];//stores all email address in the email
var participants = msgObj.participants.getArray(); //where msgObj is of type "ZmMailMsg"
for(var i =0; i < participants.length; i++) {
     if(participants[i].type == AjxEmailAddress.CC) {

 PS: Similarly you can get emails of the following types:
 AjxEmailAddress.FROM = "FROM";
 AjxEmailAddress.TO = "TO";
 AjxEmailAddress.CC = "CC";
 AjxEmailAddress.BCC = "BCC";
 AjxEmailAddress.REPLY_TO = "REPLY_TO";
 AjxEmailAddress.SENDER = "SENDER";

Get email body

var body = msgObj.getBodyContent();

Get list of attachments

var attArray =  msgObj.attachments;

//get attachments embedded in the mail body
var inlineAttachmentsArry =  msgObj.getInlineAttachments() ;

Get list of Tags

var tagsArray =  msgObj.tags;//returns array containing all the tags tagged to this message

Get List of all Emails or Conversations

The below code works when a user clicks on a panelItem when in mail app. PS: - You will have to make sure you are in mail app. - Depending on the view(Message or Conversation), the array will contain corresponding("ZmMailMsg" or "ZmConv") items

com_zimbra_test.prototype.singleClicked =
function() {
   var msgArray = appCtxt.getCurrentController().getList().getArray();

Download Entire Email

You can download the whole email(including all its attachments). This example is from com_zimbra_emaildownloader Zimlet.

The logic is to simply get the message's id and then do a simple http GET to http://<server>/home/message.txt?fmt=tgz&id=<messageId>
com_zimbra_emaildownloader.prototype.doDrop =
function(msgObj) {
	this.srcMsgObj = msgObj.srcObj;
	if(this.srcMsgObj.type == "CONV"){
		this.srcMsgObj = this.srcMsgObj.getFirstHotMsg();
	var url = [];
	var i = 0;
	var proto = location.protocol;
	var port = Number(location.port);
	url[i++] = proto;
	url[i++] = "//";
	url[i++] = location.hostname;
	if (port && ((proto == ZmSetting.PROTO_HTTP && port != ZmSetting.HTTP_DEFAULT_PORT) 
		|| (proto == ZmSetting.PROTO_HTTPS && port != ZmSetting.HTTPS_DEFAULT_PORT))) {
		url[i++] = ":";
		url[i++] = port;
	url[i++] = "/home/";
	url[i++]= AjxStringUtil.urlComponentEncode(appCtxt.getActiveAccount().name);
	url[i++] = "/message.txt?fmt=tgz&id=";
	url[i++] = this.srcMsgObj.id;

	var getUrl = url.join(""); 
	window.open(getUrl, "_blank");//do http get


Tag an email or entire conversation upon drop onto Zimlets

Assume that we have a tag by name "testTag" and want to tag any email or conversation when they are dropped onto the Zimlet.
com_zimbra_test.prototype.doDrop =
function (msgOrConvObj) {
   this.tagAction(true, msgOrConvObj.srcObj, "testTag");

com_zimbra_test.prototype.tagAction =
function (doTag, msgOrConvObj, tagName) {
        var tagObj = appCtxt.getActiveAccount().trees.TAG.getByName(tagName);
        var tagId = tagObj.id;
	var axnType = "";
	if (doTag)
		axnType = "tag"; //tag
		axnType = "!tag"; //untag

	var soapCmd = ZmItem.SOAP_CMD[msgOrConvObj.type] + "Request";
	var itemActionRequest = {};
	itemActionRequest[soapCmd] = {_jsns:"urn:zimbraMail"};
	var request = itemActionRequest[soapCmd];
	var action = request.action = {};
	action.id = msgOrConvObj.id;
	action.op = axnType;
	action.tag = tagId;
	var params = {asyncMode: true, callback: null, jsonObj:itemActionRequest};






How to override a toolbar button in mail app (to do something else)

The below code snippet allows replacing (Junk/Not Junk)aka SPAM button's functionality with a custom functionality(newSelectionListener). PS: This is only for mail app.

com_zimbra_test1.prototype.init = function() {
	//call this immediately after login to set new listner for SPAM button
	this.replaceMailToolbarBtnListener("SPAM", new AjxListener(this, this._newSelectionListener));

//Replace ALL listeners that are registered for SELECTION event with the new listner
com_zimbra_test1.prototype.replaceMailToolbarBtnListener = function(btnName, newListner) {
	var controller = null;
	var btn = null;
	//keep track of all the views for which we have already set a new listner
	if (this._viewHasNewListner == undefined) {
		this._viewHasNewListner = [];

	var viewId = appCtxt.getAppViewMgr().getCurrentViewId();
	if (viewId != ZmId.VIEW_CONVLIST && viewId != ZmId.VIEW_CONV && viewId != ZmId.VIEW_TRAD && viewId == ZmId.VIEW_MSG) {
	if (this._viewHasNewListner[viewId]) {//already has listener

	if (viewId == ZmId.VIEW_CONVLIST) {
		controller = AjxDispatcher.run("GetConvListController");
		btn = controller._toolbar.CLV.getButton(btnName);
	} else if (viewId == ZmId.VIEW_CONV) {
		controller = AjxDispatcher.run("GetConvController");
		btn = controller._toolbar.CV.getButton(btnName);
	} else if (viewId == ZmId.VIEW_TRAD) {
		controller = AjxDispatcher.run("GetTradController");
		btn = controller._toolbar.TV.getButton(btnName);
	} else if (viewId == ZmId.VIEW_MSG) {
		controller = AjxDispatcher.run("GetMsgController");
		btn = controller._toolbar.MSG.getButton(btnName);
	this._viewHasNewListner[viewId] = true;
	btn.removeSelectionListeners();//remove all earlier listners

//onShowView is called everytime a view is changed. It adds listners when user changes views(as they appear)
com_zimbra_test1.prototype.onShowView = function(viewId, isNewView) {
	if (viewId == ZmId.VIEW_CONVLIST || viewId == ZmId.VIEW_CONV || viewId == ZmId.VIEW_TRAD || viewId == ZmId.VIEW_MSG) {
		this.replaceMailToolbarBtnListener("SPAM", new AjxListener(this, this._newSelectionListener));

//New listener
com_zimbra_test1.prototype._newSelectionListener = function(obj) {
	alert("Do Something Else Here!");

How to add additional functionality to an existing button

The below code snippet allows adding more functionailty to (Junk/Not Junk)aka SPAM button's existing functionality. i.e When a user clicks on Junk button, it will mark the mail as Junk AND then calls the function newSelectionListener .

PS: Please go through the section How to override a toolbar button in mail app (to do something else) for the complete code. And simply comment the btn.removeSelectionListeners() in the function replaceMailToolbarBtnListener.

    Simply comment the btn.removeSelectionListeners() in the function replaceMailToolbarBtnListener .
  com_zimbra_test1.prototype.replaceMailToolbarBtnListener = function(btnName, newListner) {
	//btn.removeSelectionListeners();//comment this line
//New listener
com_zimbra_test1.prototype._newSelectionListener = function(obj) {
	alert("Do Something Else Here!");
Jump to: navigation, search