UNPKG

easyews

Version:

This library makes performing EWS operations from Outlook Mail Web Add-ins via JavaScript much easier.

1,023 lines (1,004 loc) 75.3 kB
/*! * easyEWS JavaScript Library v1.0.21 * http://theofficecontext.com * * Copyright David E. Craig and other contributors * Portions Copyright (c) 2020 Vijay Samtani * Released under the MIT license * https://tldrlegal.com/license/mit-license * * Date: 2022-01-25T19:42EST */ /** * The global easyEws object * @type {__nonInstanceEasyEwsClass} * */ var easyEws = new __nonInstanceEasyEwsClass(); /** * @class */ function __nonInstanceEasyEwsClass() { /** @type {string[]} */ var groups = []; /** @type {string[]} */ var processedGroups = []; /** @type {MailBoxUser[]} */ var users = []; /** @type {successCallbackMailboxUserArray} */ var splitGroupSuccessCallback; /** @type {errorCallback} */ var splitGroupErrorCallback; /** @type {debugCallback} */ var splitGroupDebugCallback; /** @type {number} */ var groupCount = 0; /*********************************************************************************************** *********************************************************************************************** *********************************************************************************************** **** * * **** * ***** *** * * * * * * * * * * **** * * **** * * * * * * * * * * * * * *** **** ***** ***** *** *********************************************************************************************** *********************************************************************************************** ***********************************************************************************************/ /** * This function finds the Parent message of a reply/forward by using the InReplyTo * field to find the InternetMessageId of the parent. * @param {string} childId The id of the item whose parent if you want to find * @param {successCallback} successCallback Returns a string with the parent id or null if there is no parent found * @param {errorCallback} errorCallback Error handler callback - function(Error) { } * @param {debugCallback} debugCallback Debug handler returns raw XML - function(String) { } */ this.getParentId = function (childId, successCallback, errorCallback, debugCallback) { /** @type {string} */ var soap = '<m:GetItem>' + ' <m:ItemShape>' + ' <t:BaseShape>AllProperties</t:BaseShape>' + ' </m:ItemShape>' + ' <m:ItemIds>' + ' <t:ItemId Id="' + childId + '"/>' + ' </m:ItemIds>' + '</m:GetItem>'; soap = getSoapHeader(soap); // make the EWS call asyncEws(soap, function (getItemXmlDoc) { /**@type {string} */ var internetMessageId = ""; try { internetMessageId = getNodes(getItemXmlDoc, "t:InReplyTo")[0].textContent; } catch(error) { // returns null if there is no InReplyTo field which likely means // that this item is not a reply or forward but a new item successCallback(null); return; } // fix the message id so it will not error internetMessageId = internetMessageId.replace("<", "&lt;").replace(">", "&gt;"); soap = '<m:FindItem Traversal="Shallow">' + ' <m:ItemShape>' + ' <t:BaseShape>IdOnly</t:BaseShape>' + ' </m:ItemShape>' + ' <m:IndexedPageItemView MaxEntriesReturned="50" Offset="0" BasePoint="Beginning" />' + ' <m:Restriction>' + ' <t:Contains ContainmentMode="Substring" ContainmentComparison="IgnoreCase">' + ' <t:FieldURI FieldURI="message:InternetMessageId" />' + ' <t:Constant Value="' + internetMessageId + '" />' + ' </t:Contains>' + ' </m:Restriction>' + ' <m:ParentFolderIds>' + ' <t:DistinguishedFolderId Id="inbox" />' + ' </m:ParentFolderIds>' + '</m:FindItem>'; soap = getSoapHeader(soap); asyncEws(soap, function (findItemXmlDoc) { var parentId = getNodes(findItemXmlDoc, "t:ItemId")[0].attributes["Id"].value; if (successCallback) successCallback(parentId); }, function (error) { if (errorCallback) errorCallback(error); }, function (debug) { if (debugCallback) debugCallback(debug); }); }, function (error) { if (errorCallback) errorCallback(error); }, function (debug) { if (debugCallback) debugCallback(debug); }); }; /** * This callback type is called 'resolveNamesCallback' and is displayed as a global symbol. * * @callback resolveNamesCallback * @param {ResolveNamesType[]} resolvedNamesArray */ /** * PUBLIC: Resolves the recipient * SEE: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/resolvenames-operation * * @param {string} recipient - The recipient name * @param {resolveNamesCallback} [successCallback] - returns 'succeeeded' is successful - function(ResolveNamesType) { } * @param {errorCallback} [errorCallback] - Error handler callback - function(Error) { } * @param {debugCallback} [debugCallback] - Debug handler returns raw XML - function(String) { } */ this.resolveRecipient = function (recipient, successCallback, errorCallback, debugCallback) { var soap = '<ResolveNames xmlns="http://schemas.microsoft.com/exchange/services/2006/messages" '+ 'xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" ' + 'ReturnFullContactData="true">' + '<UnresolvedEntry>' + recipient + '</UnresolvedEntry>' + '</ResolveNames>'; soap = getSoapHeader(soap); // make the EWS call asyncEws(soap, function (xmlDoc) { if (successCallback) { var message = getNodes(xmlDoc, "m:MessageText"); if(message != null && message.length > 0 && message[0].innerHTML == "No results were found.") { successCallback(null); } else { var returnArray = []; /**@type {XMLNode[]} */ var nodes = getNodes(xmlDoc,"t:Mailbox"); // this returns an array like this: // <t:Mailbox> // <t:Name>David Craig</t:Name> // <t:EmailAddress>decyahoo-nope@yahoo.com</t:EmailAddress> // <t:RoutingType>SMTP</t:RoutingType> // <t:MailboxType>Contact</t:MailboxType> // </t:Mailbox> for(var idx = 0; idx < nodes.length; idx++) { /**@type {XMLNode} */ var value = nodes[idx]; var name = getNodes(value, "t:Name")[0].textContent; var email = getNodes(value, "t:EmailAddress")[0].textContent; var route = getNodes(value, "t:RoutingType")[0].textContent; var box = getNodes(value, "t:MailboxType")[0].textContent; var obj = new ResolveNamesType(name, email, route, box); returnArray.push(obj); } successCallback(returnArray); } } }, function (errorDetails) { if (errorCallback != null) errorCallback(errorDetails); }, function (debug) { if (debugCallback != null) debugCallback(debug); }); }; /** * Class to hold resolved names from the ResolveNames function * @class * @param {string} name * @param {string} emailAddress * @param {string} routingType * @param {string} mailboxType * @property {string} name * @property {string} emailAddress * @property {string} routingType * @property {string} mailboxType */ function ResolveNamesType(name, emailAddress, routingType, mailboxType) { this.name = name; this.emailAddress = emailAddress; this.routiingType = routingType; this.mailboxType = mailboxType; } /** * PUBLIC: creates and sends a new email message with 1+ recipients, 0+ attachments. Can specify where to save copy. * * @param {SendMailFunctionObject} p - A sendmail object */ this.sendMailItem = function(p) { // originally, this was an ES6 initilized parameter, which is not supported in IE11 // Fix for issue #12, pull out each parameter and initialize individually // {subject, body, recipients = [""], attachments = [{name: "", mime:""}], folderid = "sentitems", successCallback, errorCallback, debugCallback} /**@type {string} */ var subject = p.subject; /**@type {string} */ var bodytype = p.bodytype.toLowerCase() == "html" ? "HTML" : "Text"; /**@type {string} */ var body = (bodytype == "HTML") ? escapeHTML(p.body) : p.body; /**@type {string[]} */ var recipients = (p.recipients !== undefined && p.recipients !== null) ? p.recipients : []; /**@type {SimpleAttachmentObject[]} */ var attachments = (p.attachments !== undefined && p.attachments !== null) ? p.attachments : [new SimpleAttachmentObject("","")]; /**@type {string[]} */ var folderid = (p.folderid !== undefined && p.folderid !== null && p.folderid !== "") ? p.folderid: "sentitems"; /**@type {successCallback} */ var successCallback = p.successCallback; /**@type {errorCallback} */ var errorCallback = p.errorCallback; /**@type {debugCallback} */ var debugCallback = p.debugCallback; //construct recipients /**@type{string} */ var xmlRecipients = ""; if(recipients === undefined || recipients === null || recipients.length == 0) { errorCallback("No recipients defined."); return; } recipients.forEach( function(address) { xmlRecipients += '<t:Mailbox><t:EmailAddress>' + address + '</t:EmailAddress></t:Mailbox>'; }); xmlRecipients = '<t:ToRecipients>' + xmlRecipients + '</t:ToRecipients>'; // construct attachments if(attachments !== undefined && attachments !== null && attachments.length > 0) { /**@type {string} */ var xmlAttachments = ""; attachments.forEach( function (attachment) { // Check if it's an empty object (ie, nothing to attach) if (attachment.name !== "" && attachment.mime !== "") { if(attachment.type == "item") { // add the item as an email/message item xmlAttachments += '<t:ItemAttachment>' + '<t:Name>' + attachment.name + '</t:Name>' + '<t:IsInline>false</t:IsInline>' + '<t:Message>' + '<t:MimeContent CharacterSet="UTF-8">' + attachment.mime + '</t:MimeContent>' + '</t:Message>' + '</t:ItemAttachment>'; } else { // add the item as a file attachment xmlAttachments += '<t:FileAttachment>' + '<t:Name>' + attachment.name + '</t:Name>' + '<t:IsInline>false</t:IsInline>' + '<t:IsContactPhoto>false</t:IsContactPhoto>' + '<t:Content>' + attachment.mime + '</t:Content>' + '</t:FileAttachment>'; } }; }); if (xmlAttachments !== "") xmlAttachments = '<t:Attachments>' + xmlAttachments + '</t:Attachments>'; } // construct folder spec to save the sent email in /**@type {string} */ var xmlSavedFolder = '<m:SavedItemFolderId><t:DistinguishedFolderId Id="' + folderid + '" /></m:SavedItemFolderId>'; // assemble the soap request /**@type {string} */ var soap = '<m:CreateItem MessageDisposition="SendAndSaveCopy">' + xmlSavedFolder + ' <m:Items>' + ' <t:Message>' + ' <t:Subject>' + subject + '</t:Subject>' + ' <t:Body BodyType="'+ bodytype + '">' + body + '</t:Body>' + xmlAttachments + xmlRecipients + ' </t:Message>' + ' </m:Items>' + '</m:CreateItem>'; soap = getSoapHeader(soap); // make the EWS call asyncEws(soap, function (xmlDoc) { // Get the required response, and if it's NoError then all has succeeded, so tell the user. // Otherwise, tell them what the problem was. (E.G. Recipient email addresses might have been // entered incorrectly --- try it and see for yourself what happens!!) /** @type {string} */ var elem = xmlDoc.getElementsByTagName("m:ResponseCode")[0]; if(elem == null) elem = xmlDoc.getElementsByTagName("ResponseCode")[0]; /**@type {string} */ var result = elem.textContent; if (result == "NoError") { successCallback(result); } else { if (errorCallback != null) errorCallback(result); } }, function (errorDetails) { if (errorCallback != null) errorCallback(errorDetails); }, function (debug) { if (debugCallback != null) debugCallback(debug); }); }; /** * PUBLIC: creates a new emails message with a single attachment and sends it * * @param {string} subject - The subject for the message to be sent * @param {string} body - The body of the message to be sent * @param {string} to - The email address of the recipient * @param {string} attachmentName - Name of the attachment * @param {string} attachmentMime - MIME content in Base64 for the attachment * @param {successCallback} successCallback - Callback with 'success' if compelted successfully - function(string) { } * @param {errorCallback} errorCallback - Error handler callback - function(string) { } * @param {debugCallback} debugCallback - Debug handler returns raw XML - function(string) { } */ this.sendPlainTextEmailWithAttachment = function (subject, body, to, attachmentName, attachmentMime, successCallback, errorCallback, debugCallback) { /**@type {SimpleAttachmentObject} */ var att = new SimpleAttachmentObject(attachmentName, attachmentMime, "item"); /**@type {SendMailFunctionObject} */ var p = new SendMailFunctionObject(subject, body, "text", [to], [att], "sentitems", successCallback, errorCallback, debugCallback); // send it this.sendMailItem(p); }; /** * PUBLIC: gets the mail item as raw MIME data * * @param {string} mailItemId - The id for the item * @param {successCallback} successCallback - Callback with email message as MIME Base64 string - function(string) { } * @param {errorCallback} errorCallback - Error handler callback - function(Error) { } * @param {debugCallback} debugCallback - Debug handler returns raw XML - function(String) { } */ this.getMailItemMimeContent = function (mailItemId, successCallback, errorCallback, debugCallback) { /** @type {string} */ var soap = '<m:GetItem>' + ' <m:ItemShape>' + ' <t:BaseShape>IdOnly</t:BaseShape>' + ' <t:IncludeMimeContent>true</t:IncludeMimeContent>' + ' </m:ItemShape>' + ' <m:ItemIds>' + ' <t:ItemId Id="' + mailItemId + '"/>' + ' </m:ItemIds>' + '</m:GetItem>'; soap = getSoapHeader(soap); // make the EWS call asyncEws(soap, function (xmlDoc) { /** @type {array} */ var nodes = getNodes(xmlDoc,"t:MimeContent"); /** @type {string} */ var content = nodes[0].textContent; successCallback(content); }, function (errorDetails) { if (errorCallback != null) errorCallback(errorDetails); }, function (debug) { if (debugCallback != null) debugCallback(debug); }); }; /** * PUBLIC: Updates the headers in the mail item * SEE: https://msdn.microsoft.com/en-us/library/office/dn596091(v=exchg.150).aspx * SEE: https://msdn.microsoft.com/en-us/library/office/dn495610(v=exchg.150).aspx * * @param {string} mailItemId - The id of the item to update * @param {string} headerName - The header item to add/update * @param {string} headerValue - The header value to update * @param {boolean} [isMeeting] - is required to be true for meeting requests * @param {successCallback} [successCallback] - returns 'succeeeded' is successful - function(String) { } * @param {errorCallback} [errorCallback] - Error handler callback - function(Error) { } * @param {debugCallback} [debugCallback] - Debug handler returns raw XML - function(String) { } */ this.updateEwsHeader = function (mailItemId, headerName, headerValue, isMeeting, successCallback, errorCallback, debugCallback) { /** @type {string} */ var firstLine = '<m:UpdateItem MessageDisposition="SaveOnly" ConflictResolution="AlwaysOverwrite">'; if(isMeeting){ firstLine = '<m:UpdateItem MessageDisposition="SaveOnly" ConflictResolution="AlwaysOverwrite" SendMeetingInvitationsOrCancellations="SendOnlyToChanged">'; } /** @type {string} */ var soap = firstLine + ' <m:ItemChanges>' + ' <t:ItemChange>' + ' <t:ItemId Id="' + mailItemId + '"/>' + ' <t:Updates>' + ' <t:SetItemField>' + ' <t:ExtendedFieldURI DistinguishedPropertySetId="InternetHeaders"' + ' PropertyName="' + headerName + '"' + ' PropertyType="String" />' + ' <t:Message>' + ' <t:ExtendedProperty>' + ' <t:ExtendedFieldURI DistinguishedPropertySetId="InternetHeaders"' + ' PropertyName="' + headerName + '"' + ' PropertyType="String" />' + ' <t:Value>' + headerValue + '</t:Value>' + ' </t:ExtendedProperty>' + ' </t:Message>' + ' </t:SetItemField>' + ' </t:Updates>' + ' </t:ItemChange>' + ' </m:ItemChanges>' + '</m:UpdateItem>'; soap = getSoapHeader(soap); // make the EWS call asyncEws(soap, function (xmlDoc) { if (successCallback) successCallback("succeeded"); }, function (errorDetails) { if (errorCallback != null) errorCallback(errorDetails); }, function (debug) { if (debugCallback != null) debugCallback(debug); }); }; /** * PUBLIC: Returns a list of items in the folder * * @param {string} folderId - The ID of the folder you want to search * @param {successCallbackArray} successCallback - Callback with array of item IDs - function(String[]) { } * @param {errorCallback} errorCallback - Error handler callback - function(Error) { } * @param {errorCallback} errorCallback - Debug handler returns raw XML - function(String) { } */ this.getFolderItemIds = function (folderId, successCallback, errorCallback, debugCallback) { /** @type {string} */ var soap = '<m:FindItem Traversal="Shallow">' + ' <m:ItemShape> ' + ' <t:BaseShape>IdOnly</t:BaseShape>' + ' </m:ItemShape>' + ' <m:ParentFolderIds>' + ' <t:FolderId Id="' + folderId + '"/>' + ' </m:ParentFolderIds>' + '</m:FindItem>'; /** @type {array} */ var returnArray = []; soap = getSoapHeader(soap); // call ews asyncEws(soap, function (xmlDoc) { /** @type {XMLNode} */ var nodes = getNodes(xmlDoc, "t:ItemId"); // loop through and return an array of ids for(var idx=0;idx<nodes.length;idx++) { returnArray.push(nodes[idx].getAttribute("Id")); } // $.each(nodes, function (index, value) { // returnArray.push(value.getAttribute("Id")); // }); successCallback(returnArray); }, function (errorDetails) { if (errorCallback != null) { errorCallback(errorDetails); } }, function (debug) { if (debugCallback != null) debugCallback(debug); }); }; /** * PUBLIC: Gets the item details for a specific item by ID * * @param {string} itemId The ID for the item * @param {successCallbackMailItem} successCallback - Callback with the details of the MailItem - function(MailItem) { } * @param {errorCallback} errorCallback - Error handler callback - function(Error) { } * @param {debugCallback} debugCallback - Debug handler returns raw XML - function(String) { } */ this.getMailItem = function (itemId, successCallback, errorCallback, debugCallback) { /** @type {string} */ var soap = '<m:GetItem>' + ' <m:ItemShape>' + ' <t:BaseShape>Default</t:BaseShape>' + ' <t:IncludeMimeContent>true</t:IncludeMimeContent>' + ' </m:ItemShape>' + ' <m:ItemIds>' + ' <t:ItemId Id="' + itemId + '" />' + ' </m:ItemIds>' + '</m:GetItem>'; soap = getSoapHeader(soap); // make call to EWS asyncEws(soap, function (xmlDoc) { /** @type {MailItem} */ var item = new MailItem(xmlDoc); successCallback(item); }, function (errorDetails) { if(errorCallback != null) { errorCallback(errorDetails); } }, function (debug) { if (debugCallback != null) debugCallback(debug); }); }; /** * PUBLIC: Splits groups and groups in groups, async, until all users are * found and added to the list. The list of MailBoxUsers[] is * returned as a paramater of the success callback. * NOTE: For performance reasons, this will STOP splitting groups after 10 * levels deeps. If groups nesting is greater than this it is bad design * on the Exchange organization * @param {string[]} groupList The alias for the group(s) to be split * @param {successCallbackMailboxUserArray} sucessCallback Callback with array of MailBoxUsers - function(MailBoxUser[]) { } * @param {errorCallback} errorCallback - Error handler callback - function(Error) { } * @param {debugCallback} debugCallback - Debug handler returns raw XML - function(String) { } */ this.splitGroupsAsync = function(groupList, successCallback, errorCallback, debugCallback) { // cleanup - reset arrays groups = []; users = []; processedGroups = []; groupCount = 0; // add the current groups groups.push(groupList); // set callbacks splitGroupSuccessCallback = successCallback; splitGroupErrorCallback = errorCallback; splitGroupDebugCallback = debugCallback; // now start... splitGroupsRecursivelyAsync(); }; /** * PUBLIC: Expands a group and returns all the members * NOTE: Does not enumerate groups in groups * * @param {string} group The alias for the group to be expanded * @param {successCallbackMailboxUserArray} successCallback - Callback with array of MailBoxUsers - function(MailBoxUser[]) { } * @param {errorCallback} errorCallback - Error handler callback - function(Error) { } * @param {errorCallback} errorCallback - Debug handler returns raw XML - function(String) { } */ this.expandGroup = function (group, successCallback, errorCallback, debugCallback) { // NOTE: Some groups might have an unsafe character like & // So, here we first make sure there is not a mix first by // converting already safe to unsafe, then converting everything // to a safe format. // NOTE: Confirmed in O365 - unable to create groups with & // NOTE: Confirmed in EX2106/2019 - able to create groups with & // Microsoft Offical documentation on the matter: // https://docs.microsoft.com/en-us/office365/troubleshoot/active-directory/email-address-contain-underscore // NOTE: Fixed per issue #8: Expanding groups with '&' ampersand in the group /** @type {string} */ var safeGroup = group.replace('&amp;', '&').replace('&', '&amp;'); /** @type {string} */ var soap = '<m:ExpandDL>' + ' <m:Mailbox>' + ' <t:EmailAddress>' + safeGroup + '</t:EmailAddress>' + ' </m:Mailbox>' + '</m:ExpandDL>'; soap = getSoapHeader(soap); // make the EWS call /** @type {array} */ var returnArray = []; asyncEws(soap, function (xmlDoc) { /** @type {array} */ var extendedProps = getNodes(xmlDoc, "t:Mailbox"); // loop through and return an array of properties for(var idx=0; idx<extendedProps.length; idx++) { returnArray.push(new MailboxUser(extendedProps[idx])); } // $.each(extendedProps, function (index, value) { // returnArray.push(new MailboxUser(value)); // }); successCallback(returnArray); }, function (errorDetails) { if (errorCallback != null) errorCallback(errorDetails); }, function (debug) { if (debugCallback != null) debugCallback(debug); }); }; /** * PUBLIC: Find a given conversation by the ID * NOTE: Search for parent: * http://stackoverflow.com/questions/19008696/exchange-find-items-in-ews-conversation-using-xml-request * http://www.outlookcode.com/codedetail.aspx?id=1714 * https://msdn.microsoft.com/en-us/library/office/dn610351(v=exchg.150).aspx * * @param {string} converstionId - The conversation to find * @param {successCallbackArray} successCallback - Callback with array of item IDs - function(String[]) { } * @param {errorCallback} errorCallback - Error handler callback - function(Error) { } * @param {errorCallback} errorCallback - Debug handler returns raw XML - function(String) { } */ this.findConversationItems = function (conversationId, successCallback, errorCallback, debugCallback) { /** @type {string} */ var soap = ' <m:GetConversationItems>' + ' <m:ItemShape>' + ' <t:BaseShape>IdOnly</t:BaseShape>' + ' <t:AdditionalProperties>' + ' <t:FieldURI FieldURI="item:Subject" />' + ' <t:FieldURI FieldURI="item:DateTimeReceived" />' + ' </t:AdditionalProperties>' + ' </m:ItemShape>' + ' <m:FoldersToIgnore>' + ' <t:DistinguishedFolderId Id="deleteditems" />' + ' <t:DistinguishedFolderId Id="drafts" />' + ' </m:FoldersToIgnore>' + ' <m:SortOrder>TreeOrderDescending</m:SortOrder>' + ' <m:Conversations>' + ' <t:Conversation>' + ' <t:ConversationId Id="' + conversationId + '" />' + ' </t:Conversation>' + ' </m:Conversations>' + ' </m:GetConversationItems>'; soap = getSoapHeader(soap); // Make EWS call asyncEws(soap, function (xmlDoc) { /** @type {array} */ var returnArray = []; try { /** @type {array} */ var nodes = getNodes(xmlDoc, "t:ItemId"); if (nodes == null) { if (errorCallback != null) { errorCallback(new Error("The XML returned from the server could not be parsed.")); } } else if (nodes.length == 0) { successCallback(null); } else { // loop through and return an array of ids for(var idx=0; idx < nodes.length; idx++) { returnArray.push(nodes[idx].getAttribute("Id")); } // $.each(nodes, function (index, value) { // returnArray.push(value.getAttribute("Id")); // }); successCallback(returnArray); } } catch (error) { if (errorCallback != null) errorCallback(error); } }, function (errorDetails) { if (errorCallback != null) errorCallback(errorDetails); }, function (debug) { if (debugCallback != null) debugCallback(debug); }); }; /** * PUBLIC: Gets a specific Internet header for a spific item * NOTE: https://msdn.microsoft.com/en-us/library/office/aa566013(v=exchg.150).aspx * * @param {string} itemId - The item ID to get * @param {string} headerName - The header to get * @param {string} headerType - The header type (String, Integer) * @param {successCallback} successCallback - Returns the value for the header - function(string) { } * @param {errorCallback} errorCallback - Error handler callback - function(Error) { } * @param {errorCallback} errorCallback - Debug handler returns raw XML - function(String) { } */ this.getSpecificHeader = function (itemId, headerName, headerType, successCallback, errorCallback, debugCallback) { /** @type {string} */ var soap = ' <m:GetItem>' + ' <m:ItemShape>' + ' <t:BaseShape>IdOnly</t:BaseShape>' + ' <t:AdditionalProperties>' + ' <t:ExtendedFieldURI DistinguishedPropertySetId="InternetHeaders" PropertyName="' + headerName + '" PropertyType="' + headerType + '" />' + ' </t:AdditionalProperties>' + ' </m:ItemShape>' + ' <m:ItemIds>' + ' <t:ItemId Id="' + itemId + '" />' + ' </m:ItemIds>' + ' </m:GetItem>'; soap = getSoapHeader(soap); // Make the EWS call /** @type {string} */ var returnValue = ""; asyncEws(soap, function (xmlDoc) { try { if (xmlDoc == null) { successCallback(null); return; } /** @type {array} */ var nodes = getNodes(xmlDoc, "t:ExtendedProperty"); for(var idx=0;idx < nodes.length; idx++) { /**@type {XMLNode} */ var value = nodes[idx]; /** @type {string} */ var nodeName = getNodes(value, "t:ExtendedFieldURI")[0].getAttribute("PropertyName"); /** @type {string} */ var nodeValue = getNodes(value, "t:Value")[0].textContent; if (nodeName == headerName) { returnValue = nodeValue; } } // $.each(nodes, function (index, value) { // /** @type {string} */ // var nodeName = getNodes(value, "t:ExtendedFieldURI")[0].getAttribute("PropertyName"); // /** @type {string} */ // var nodeValue = getNodes(value, "t:Value")[0].textContent; // if (nodeName == headerName) { // returnValue = nodeValue; // } // }); successCallback(returnValue); } catch (error) { if (errorCallback != null) errorCallback(error); } }, function (errorDetails) { if (errorCallback != null) errorCallback(errorDetails); }, function (debug) { if (debugCallback != null) debugCallback(debug); }); }; /** * PUBLIC: Gets Internet headers for a spific item * NOTE: https://msdn.microsoft.com/en-us/library/office/aa566013(v=exchg.150).aspx * * @param {string} itemId - The item ID to get * @param {successCallbackDictionary} successCallback - Callback with a Dictionary(key,value) containing the message headers - function(Dictionary) { } * @param {errorCallback} errorCallback - Error handler callback - function(Error) { } * @param {errorCallback} errorCallback - Debug handler returns raw XML - function(String) { } */ this.getEwsHeaders = function (itemId, successCallback, errorCallback, debugCallback) { /** @type {string} */ var soap = ' <m:GetItem>' + ' <m:ItemShape>' + ' <t:BaseShape>AllProperties</t:BaseShape>' + ' <t:IncludeMimeContent>true</t:IncludeMimeContent>' + ' </m:ItemShape>' + ' <m:ItemIds>' + ' <t:ItemId Id="' + itemId + '" />' + ' </m:ItemIds>' + ' </m:GetItem>'; soap = getSoapHeader(soap); // Make the EWS call /** @type {Dictionary} */ var returnArray = new Dictionary(); asyncEws(soap, function (xmlDoc) { try { if (xmlDoc == null) { successCallback(null); return; } /** @type {array} */ var nodes = getNodes(xmlDoc, "t:InternetMessageHeader"); if(nodes !== null && nodes != undefined) { for(var i=0;i<nodes.length;i++) { returnArray.add(nodes[i].getAttribute("HeaderName"), nodes[i].textContent); } successCallback(returnArray); } else { successCallback(null); // no headers found } } catch (error) { if (errorCallback != null) errorCallback(error); } }, function (errorDetails) { if (errorCallback != null) errorCallback(errorDetails); }, function (debug) { if (debugCallback != null) debugCallback(debug); }); }; /** * PUBLIC: Updates a folder property. If the property does not exist, it will be created. * * @param {string} folderId - The ID for the folder * @param {string} propName - The property on the folder to set * @param {string} propValue - The value for the propert * @param {successCallback} successCallback - returns 'succeeeded' is successful - function(String) { } * @param {errorCallback} errorCallback - Error handler callback - function(Error) { } * @param {debugCallback} debugCallback - Debug handler returns raw XML - function(String) { } */ this.updateFolderProperty = function (folderId, propName, propValue, successCallback, errorCallback, debugCallback) { /** @type {string} */ var soap = ' <m:UpdateFolder>' + ' <m:FolderChanges>' + ' <t:FolderChange>' + ' <t:FolderId Id="' + folderId + '" />' + ' <t:Updates>' + ' <t:SetFolderField>' + ' <t:ExtendedFieldURI ' + ' DistinguishedPropertySetId="PublicStrings" ' + ' PropertyName="' + propName + '" ' + ' PropertyType="String" />' + ' <t:Folder>' + ' <t:ExtendedProperty>' + ' <t:ExtendedFieldURI ' + ' DistinguishedPropertySetId="PublicStrings" ' + ' PropertyName="' + propName + '" ' + ' PropertyType="String" />' + ' <t:Value>' + propValue + '</t:Value>' + ' </t:ExtendedProperty>' + ' </t:Folder>' + ' </t:SetFolderField>' + ' </t:Updates>' + ' </t:FolderChange>' + ' </m:FolderChanges>' + ' </m:UpdateFolder>'; soap = getSoapHeader(soap); // make the EWS call asyncEws(soap, function(data) { if(successCallback != null) successCallback('succeeeded'); }, function (error) { if (errorCallback != null) errorCallback(error); }, function (debug) { if (debugCallback != null) debugCallback(debug); }); }; /** * PUBLIC: Gets a folder property * * @param {string} folderId - The ID for the folder * @param {string} propName - The property to get * @param {successCallback} successCallback - returns the folder property value if successful - function(String) { } * @param {errorCallback} errorCallback - Error handler callback - function(Error) { } * @param {debugCallback} debugCallback - Debug handler returns raw XML - function(String) { } */ this.getFolderProperty = function (folderId, propName, successCallback, errorCallback, debugCallback) { /** @type {string} */ var soap = '<m:GetFolder>' + '<m:FolderShape>' + '<t:BaseShape>IdOnly</t:BaseShape>' + '<t:AdditionalProperties>' + '<t:ExtendedFieldURI ' + ' DistinguishedPropertySetId="PublicStrings" ' + ' PropertyName="' + propName + '" ' + ' PropertyType="String" />' + '</t:AdditionalProperties>' + '</m:FolderShape>' + '<m:FolderIds>' + '<t:FolderId Id="' + folderId + '"/>' + '</m:FolderIds>' + '</m:GetFolder>'; soap = getSoapHeader(soap); // make the EWS call asyncEws(soap, function (xmlDoc) { /** @type {array} */ var nodes = getNodes(xmlDoc, "t:Value"); // return the content of the node if (nodes.length > 0) { successCallback(nodes[0].textContent); } else { successCallback(null); // no property found } }, function (error) { if (errorCallback != null) errorCallback(error); }, function (debug) { if (debugCallback != null) debugCallback(debug); }); }; /** * PUBLIC: Gets the folder id by the given name from the store * * @param {string} folderName - Name of the folder to get the ID for * @param {successCallback} successCallback - returns the folder ID if successful - function(String) { } * @param {errorCallback} errorCallback - Error handler callback - function(Error) { } * @param {debugCallback} debugCallback - Debug handler returns raw XML - function(String) { } */ this.getFolderId = function (folderName, successCallback, errorCallback, debugCallback) { /** @type {string} */ var soap = ' <m:GetFolder>' + ' <m:FolderShape>' + ' <t:BaseShape>IdOnly</t:BaseShape>' + ' </m:FolderShape>' + ' <m:FolderIds>' + ' <t:DistinguishedFolderId Id="' + folderName + '" />' + ' </m:FolderIds>' + ' </m:GetFolder>'; soap = getSoapHeader(soap); // make EWS callback asyncEws(soap, function (xmlDoc) { /** @type {array} */ var nodes = getNodes(xmlDoc, "t:FolderId"); if (nodes.length > 0) { /** @type {string} */ var id = nodes[0].getAttribute("Id"); successCallback(id); } else { errorCallback("Unable to get folder ID"); } }, function (errorDetails) { if (errorCallback != null) errorCallback(errorDetails); }, function (debug) { if (debugCallback != null) debugCallback(debug); }); }; /** * PUBLIC: Moves an item to the specified folder * * @param {string} itemId - the item to be moved * @param {string} folderId - Name or ID of the folder where the item will be moved * @param {successCallback} successCallback - returns the folder ID if successful - function(String) { } * @param {errorCallback} errorCallback - Error handler callback - function(Error) { } * @param {debugCallback} debugCallback - Debug handler returns raw XML - function(String) { } */ this.moveItem = function(itemId, folderId, successCallback, errorCallback, debugCallback) { /** @type {string} */ var soap = '<MoveItem xmlns="http://schemas.microsoft.com/exchange/services/2006/messages"' + ' xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">' + ' <ToFolderId>' + ' <t:DistinguishedFolderId Id="' + folderId + '"/>' + ' </ToFolderId>' + ' <ItemIds>' + ' <t:ItemId Id="' + itemId + '"/>' + ' </ItemIds>' + '</MoveItem>'; soap = getSoapHeader(soap); // make EWS callback asyncEws(soap, function (data) { if(successCallback != null) successCallback('succeeeded'); }, function (errorDetails) { if (errorCallback != null) errorCallback(errorDetails); }, function (debug) { if (debugCallback != null) debugCallback(debug); }); }; /** * PUBLIC: Gets all the recipients from the To/CC/BCC lines * NOTE: Requires the Office.js library to be loaded as it uses its types * * @param {Office.Types.ItemCompose} composeItem - the cast of the Office.context.mailbox.item * @param {getAllRecipientsCallbackDelegate} successCallback - called when completed function(Office.EmailAddressDetails[], Office.EmailAddressDetails[]) { } * @param {errorCallbackDelegate} errorCallback - Error handler callback - function(Error) { } */ this.getAllRecipientsAsync = function(composeItem, successCallback, errorCallback) { /** @type {Office.EmailAddressDetails[]} */ var users = []; /** @type {Office.EmailAddressDetails[]} */ var groups = []; // get the TO line composeItem.to.getAsync(function(toAsyncResult) { if(toAsyncResult.error) { errorCallback(error); } else { /** @type {Office.Recipients} */ var recipients = toAsyncResult.value; // if there are results, add them to the return array if(recipients.length > 0) { recipients.forEach( /** * @param {Office.EmailAddressDetails} recip * @param {Number} index */ function(recip, index) { if(recip.recipientType == Office.MailboxEnums.RecipientType.DistributionList) { /** @type {Boolean} */ var found = false; for(var i=0; i<groups.length;i++) { /** @param {EmailAddressDetails} */ var item = groups[i]; if(item.emailAddress == recip.emailAddress) { found = true; break; } } if(!found) { groups.push(recip); } } else { /** @type {Boolean} */ var found = false; for(var i=0;i<users.length;i++) { /** @param {Office.EmailAddressDetails} */ var item = users[i]; if(item.emailAddress == recip.emailAddress) { found = true; break; } } if(!found) { users.push(recip); } } } ); } // get the CC line composeItem.cc.getAsync(function(ccAsyncResult) { if(ccAsyncResult.error) { errorCallback(error); } else { /** @type {Office.Recipients} */ var recipients = ccAsyncResult.value; // if we have results if(recipients.length > 0) { recipients.forEach( /** * @param {Office.EmailAddressDetails} recip * @param {Number} index */ function(recip, index) { if(recip.recipientType == Office.MailboxEnums.Rec