I am actually writing a SOAP command (from javascript) for an Outlook Add-In that sends a mail (to run on an Exchange Server). In the mail, I want to include 2 hyperlinks in 2 different lines. As of now, the code is as follows;
{
var soapNotificationItem = '<?xml version="1.0" encoding="utf-8"?>' +
'<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"' +
' xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"' +
' xmlns:xsd="http://www.w3.org/2001/XMLSchema"' +
' xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"' +
' xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">' +
' <soap:Header>' +
' <RequestServerVersion Version="Exchange2013" xmlns="http://schemas.microsoft.com/exchange/services/2006/types" soap:mustUnderstand="0" />' +
' </soap:Header>' +
' <soap:Body>' +
' <m:CreateItem MessageDisposition="SendAndSaveCopy">' +
' <m:Items>' +
'<t:Message>'+
'<t:Subject>Notification email</t:Subject>'+
'<t:Body BodyType="HTML">' + MyMessage + '</t:Body>' +
' <t:ExtendedProperty>' +
' <t:ExtendedFieldURI PropertyTag="16367" PropertyType="SystemTime" />'+
'<t:Value>2014-01-02T21:09:52.000</t:Value>'+
'</t:ExtendedProperty>'+
'<t:ToRecipients>' + MyMailAdd + '</t:ToRecipients>' +
'</t:Message>'+
' </m:Items>' +
' </m:CreateItem>' +
' </soap:Body>' +
'</soap:Envelope>';
mailbox.makeEwsRequestAsync(soapNotificationItem, soapNotificationItemCallback);
}
As you can see, I have my parameter MyMessage, which I am constructing separately, as represented in the below example;
MyMessage = "www.mylink1.com" + "
" + "www.mylink2.com"
Any Idea how I make hyperlinks out of the 2 links with a line break in between. The
does not work either.
Finally I managed to find a solution to the issue. By specifying the Body type to HTML <t:Body BodyType="HTML">, I have been able to add simple HTML.
To simplify, the HTML construction follows the below format, though in my case, I was reading the data from a XML file, looping and concatenating the message to be displayed.
var link1 = "www.test.com"
var MyMessage = "<strong>Click on link :</strong>: " + Link1 + "";
Then coming to the SOAP part, it remains as is;
{
var soapNotificationItem = '<?xml version="1.0" encoding="utf-8"?>' +
'<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"' +
' xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"' +
' xmlns:xsd="http://www.w3.org/2001/XMLSchema"' +
' xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"' +
' xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">' +
' <soap:Header>' +
' <RequestServerVersion Version="Exchange2013" xmlns="http://schemas.microsoft.com/exchange/services/2006/types" soap:mustUnderstand="0" />' +
' </soap:Header>' +
' <soap:Body>' +
' <m:CreateItem MessageDisposition="SendAndSaveCopy">' +
' <m:Items>' +
'<t:Message>'+
'<t:Subject>Notification email</t:Subject>'+
'<t:Body BodyType="HTML">' + MyMessage + '</t:Body>' +
' <t:ExtendedProperty>' +
' <t:ExtendedFieldURI PropertyTag="16367" PropertyType="SystemTime" />'+
'<t:Value>2014-01-02T21:09:52.000</t:Value>'+
'</t:ExtendedProperty>'+
'<t:ToRecipients>' + MyMailAdd + '</t:ToRecipients>' +
'</t:Message>'+
' </m:Items>' +
' </m:CreateItem>' +
' </soap:Body>' +
'</soap:Envelope>';
mailbox.makeEwsRequestAsync(soapNotificationItem, soapNotificationItemCallback);
}
NOTE: for the link to appear correctly in Office365, do add the # in front of the link.
Related
I am trying to create en ePub using the JSZIP javascript library but the output (i.e. epub.epub file) is not usable/reable
The following code does not work :
// Create a new ZIP file
var zip = new JSZip();
// Set the metadata for the book
var metadata = '<?xml version="1.0"?>' +
'<package xmlns="http://www.idpf.org/2007/opf">' +
' <metadata>' +
' <dc:title>My Book</dc:title>' +
' <dc:author>John Smith</dc:author>' +
' </metadata>' +
' <manifest>' +
' <item id="text" href="text.txt" media-type="application/xhtml+xml"/>' +
' <item id="toc" href="toc.ncx" media-type="application/x-dtbncx+xml"/>' +
' </manifest>' +
' <spine>' +
' <itemref idref="text"/>' +
' </spine>' +
'</package>';
zip.file("content.opf", metadata);
// Set the table of contents for the book
var toc = '<?xml version="1.0"?>' +
'<ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1">' +
' <head>' +
' <meta name="dtb:uid" content="book-id"/>' +
' <meta name="dtb:depth" content="1"/>' +
' <meta name="dtb:totalPageCount" content="0"/>' +
' <meta name="dtb:maxPageNumber" content="0"/>' +
' </head>' +
' <docTitle>' +
' <text>My Book</text>' +
' </docTitle>' +
' <navMap>' +
' <navPoint id="navpoint-1" playOrder="1">' +
' <navLabel>' +
' <text>Chapter 1</text>' +
' </navLabel>' +
' <content src="text.txt#xpointer(/html/body/p[1])"/>' +
' </navPoint>' +
' <navPoint id="navpoint-2" playOrder="2">' +
' <navLabel>' +
' <text>Chapter 2</text>' +
' </navLabel>' +
' <content src="text.txt#xpointer(/html/body/p[5])"/>' +
' </navPoint>' +
' </navMap>' +
'</ncx>';
zip.file("toc.ncx", toc);
// Add the text of the book to the ZIP file
// Add the text of the book to the ZIP file
zip.file("text.txt", "Chapter 1\n\nThis is the text for chapter 1.\n\nChapter 2\n\nThis is the text for chapter 2.");
// Generate a downloadable EPUB file from the ZIP file
zip.generateAsync({ type: "blob" })
.then(function (blob) {
saveAs(blob, "epub.epub");
});
Could you please help me find a solution or redirect toward an existing library ?
I want to be able to use it within a chrome extension, I tried jEpub but it is blocked by chrome.
There are a number of issues with your EPUB generation which would suggest you haven't read through the OPF specification which can be found here: https://idpf.org/epub/30/spec/epub30-ocf.html
The (main) issues are:
Missing metadata file
Incorrect structure (best practice)
OPF file missing version package version
You're using the dc namespace without it being defined. Define it.
Missing required dc elements such as dc:identifier.
dc:author doesn't exist as an element. Use dc:creator instead
Your spine should declare toc="toc"
Pages should be of type .xhtml
You should also include a nav file
Here is a working version of your script:
var zip = new JSZip();
// Set the metadata for the book
var mimetype = 'application/epub+zip';
zip.file("mimetype", mimetype);
var container = '<?xml version="1.0"?>' +
'<container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">' +
' <rootfiles>' +
' <rootfile full-path="OEBPS/content.opf" media-type="application/oebps-package+xml" />' +
' </rootfiles>' +
'</container>';
zip.file("META-INF/container.xml", container);
var metadata = '<?xml version="1.0"?>' +
'<package version="3.0" xml:lang="en" xmlns="http://www.idpf.org/2007/opf" unique-identifier="book-id">' +
' <metadata xmlns:dc="http://purl.org/dc/elements/1.1/">' +
' <dc:identifier id="book-id">urn:uuid:B9B412F2-CAAD-4A44-B91F-A375068478A0</dc:identifier>' +
' <meta refines="#book-id" property="identifier-type" scheme="xsd:string">uuid</meta>' +
' <meta property="dcterms:modified">2000-03-24T00:00:00Z</meta>' +
' <dc:language>en</dc:language>' +
' <dc:title>My Book</dc:title>' +
' <dc:creator>John Smith</dc:creator>' +
' </metadata>' +
' <manifest>' +
' <item id="text" href="text.xhtml" media-type="application/xhtml+xml"/>' +
' <item id="toc" href="../OEBPS/toc.ncx" media-type="application/x-dtbncx+xml"/>' +
' </manifest>' +
' <spine toc="toc">' +
' <itemref idref="text"/>' +
' </spine>' +
'</package>';
zip.file("OEBPS/content.opf", metadata);
// Set the table of contents for the book
var toc = '<?xml version="1.0"?>' +
'<ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1">' +
' <head>' +
' <meta name="dtb:uid" content="urn:uuid:B9B412F2-CAAD-4A44-B91F-A375068478A0"/>' +
' <meta name="dtb:depth" content="1"/>' +
' <meta name="dtb:totalPageCount" content="0"/>' +
' <meta name="dtb:maxPageNumber" content="0"/>' +
' </head>' +
' <docTitle>' +
' <text>My Book</text>' +
' </docTitle>' +
' <navMap>' +
' <navPoint id="navpoint-1" playOrder="1">' +
' <navLabel>' +
' <text>Chapter 1</text>' +
' </navLabel>' +
' <content src="text.xhtml#xpointer(/html/body/section[1])"/>' +
' </navPoint>' +
' <navPoint id="navpoint-2" playOrder="2">' +
' <navLabel>' +
' <text>Chapter 2</text>' +
' </navLabel>' +
' <content src="text.xhtml#xpointer(/html/body/section[2])"/>' +
' </navPoint>' +
' </navMap>' +
'</ncx>';
zip.file("OEBPS/toc.ncx", toc);
// Add the text of the book to the ZIP file
// Add the text of the book to the ZIP file
var text = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>' +
'<!DOCTYPE html>' +
'<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops" xml:lang="en" lang="en">' +
' <head>' +
' <title>My Book</title>' +
' </head>' +
' <body>' +
' <section><h1>Chapter 1</h1>' +
' <p>This is the text for chapter 1.</p>' +
' </section>' +
' <section><h1>Chapter 2</h1>' +
' <p>This is the text for chapter 2.</p>' +
' </section>' +
' </body>' +
'</html>';
zip.file("OEBPS/text.xhtml", text);
// Generate a downloadable EPUB file from the ZIP file
zip.generateAsync({ type: "blob" }).then(function (blob) {
saveAs(blob, "epub.epub");
});
Ensure that you also run your generated EPUB against a validator to debug. Something like https://draft2digital.com/book/epubcheck/upload is good.
I'm trying to use the EWS DeleteItem operation, and here's how I'm calling it:
var mailbox = Office.context.mailbox;
var item = Office.cast.item.toItemRead(mailbox.item);
var requestResponse = mailbox.makeEwsRequestAsync(getDeleteItemRequest(item.itemId), callback2);
Here is my getDeleteItemRequest function:
function getDeleteItemRequest(id) {
var result = '<?xml version="1.0" encoding="utf-8"?> ' +
'<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:t="https://schemas.microsoft.com/exchange/services/2006/types"> ' +
'<soap:Body> ' +
'<DeleteItem DeleteType="HardDelete" xmlns="https://schemas.microsoft.com/exchange/services/2006/messages"> ' +
'<ItemIds> ' +
'<t:ItemId Id="' + id + '" /> ' +
'</ItemIds> ' +
'</DeleteItem> ' +
'</soap:Body> ' +
'</soap:Envelope>';
return result;
}
But, I always get back ErrorInvalidRequest and the item is never deleted.
It is Exchange 2013 that I'm using. Why is this failing to delete the item?
Thanks!
DeleteItem isn't allowed in an Addin, only a subset of EWS Request are they are listed in https://learn.microsoft.com/en-us/office/dev/add-ins/outlook/web-services. You can use MoveItem or set a specific retention tag on the Item as an alternative.
In you request the XML schema definitions are wrong Microsoft did a mass update on the documentation and broke most EWS request (the changed http to https in the schema declaration which the server won't accept) so your request
function getMoveItemRequest(id, changeKey) {
var result =
'<?xml version="1.0" encoding="utf-8"?> ' +
'<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' +
'xmlns:xsd="http://www.w3.org/2001/XMLSchema" ' +
'xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" ' +
'xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"> ' +
'<soap:Header> ' +
'<t:RequestServerVersion Version="Exchange2013" xmlns="http://schemas.microsoft.com/exchange/services/2006/types" soap:mustUnderstand="0" /> ' +
'</soap:Header> ' +
'<soap:Body> ' +
'<MoveItem xmlns="https://schemas.microsoft.com/exchange/services/2006/messages" ' +
'xmlns:t="https://schemas.microsoft.com/exchange/services/2006/types"> ' +
'<ToFolderId> ' +
'<t:DistinguishedFolderId Id="deleteditems"/> ' +
'</ToFolderId> ' +
'<ItemIds> ' +
'<t:ItemId Id="' + id + '" ChangeKey="' + changeKey + '"/> ' +
'</ItemIds> ' +
'</MoveItem> ' +
'</soap:Body> ' +
'</soap:Envelope> ';
return result;
}
should be
function getMoveItemRequest(id, changeKey) {
var result =
'<?xml version="1.0" encoding="utf-8"?> ' +
'<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' +
'xmlns:xsd="http://www.w3.org/2001/XMLSchema" ' +
'xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" ' +
'xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"> ' +
'<soap:Header> ' +
'<t:RequestServerVersion Version="Exchange2013" xmlns="http://schemas.microsoft.com/exchange/services/2006/types" soap:mustUnderstand="0" /> ' +
'</soap:Header> ' +
'<soap:Body> ' +
'<MoveItem xmlns="http://schemas.microsoft.com/exchange/services/2006/messages" ' +
'xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"> ' +
'<ToFolderId> ' +
'<t:DistinguishedFolderId Id="deleteditems"/> ' +
'</ToFolderId> ' +
'<ItemIds> ' +
'<t:ItemId Id="' + id + '" ChangeKey="' + changeKey + '"/> ' +
'</ItemIds> ' +
'</MoveItem> ' +
'</soap:Body> ' +
'</soap:Envelope> ';
return result;
}
I'm trying to delete an item using the EWS MoveItem XML request. I'm sending this request to the makeEwsRequestAsync function:
function getMoveItemRequest(id, changeKey) {
var result =
'<?xml version="1.0" encoding="utf-8"?>' +
'<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:t="https://schemas.microsoft.com/exchange/services/2006/types">' +
'<soap:Header>' +
'<RequestServerVersion Version="Exchange2013" xmlns="http://schemas.microsoft.com/exchange/services/2006/types" soap:mustUnderstand="0" />' +
'</soap:Header>' +
'<soap:Body>' +
'<MoveItem xmlns="https://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="https://schemas.microsoft.com/exchange/services/2006/types">' +
'<ToFolderId>' +
'<t:DistinguishedFolderId Id="deleteditems" />' +
'</ToFolderId>' +
'<ItemIds>' +
'<t:ItemId Id="' + id + '" ChangeKey="' + changeKey + '" />' +
'</ItemIds>' +
'</MoveItem>' +
'</soap:Body>' +
'</soap:Envelope>';
return result;
}
I'm getting the item id from the message like this:
Office.context.mailbox.item.itemId
I'm getting changekey like this:
var mailbox = Office.context.mailbox;
var soapToGetItemData = getItemDataRequest(mailbox.item.itemId);
Office.context.mailbox.makeEwsRequestAsync(soapToGetItemData, function(result) {
var response = $.parseXML(result.value);
var responseString = result.value;
// TODO: May want to reconsider the logic for getting the ChangeKey
var indexOfChangeKey = responseString.indexOf("ChangeKey=\"");
var substringAfterChangeKey = responseString.substring(indexOfChangeKey + 11);
var indexOfQuotes = substringAfterChangeKey.indexOf("\"");
var changeKey = substringAfterChangeKey.substring(0, indexOfQuotes);
Here is the getItemDataRequest function:
function getItemDataRequest(itemId) {
var soapToGetItemData = '<?xml version="1.0" encoding="utf-8"?>' +
'<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"' +
' xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"' +
' xmlns:xsd="http://www.w3.org/2001/XMLSchema"' +
' xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"' +
' xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">' +
' <soap:Header>' +
' <RequestServerVersion Version="Exchange2013" xmlns="http://schemas.microsoft.com/exchange/services/2006/types" soap:mustUnderstand="0" />' +
' </soap:Header>' +
' <soap:Body>' +
' <GetItem' +
' xmlns="http://schemas.microsoft.com/exchange/services/2006/messages"' +
' xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">' +
' <ItemShape>' +
' <t:BaseShape>IdOnly</t:BaseShape>' +
' <t:AdditionalProperties>' +
' <t:FieldURI FieldURI="item:Attachments" /> ' +
' </t:AdditionalProperties> ' +
' </ItemShape>' +
' <ItemIds>' +
' <t:ItemId Id="' + itemId + '"/>' +
' </ItemIds>' +
' </GetItem>' +
' </soap:Body>' +
'</soap:Envelope>';
return soapToGetItemData;
}
Yet, I'm getting an invalid response from this (the XML that is returned has "<faultstring xml:lang="en-US">The request is invalid." in it.)
Any ideas what's going on?
Thanks!
Needed to use http instead of https in the request.
function getMoveItemRequest(id, changeKey) {
var result =
'<?xml version="1.0" encoding="utf-8"?> ' +
'<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' +
'xmlns:xsd="http://www.w3.org/2001/XMLSchema" ' +
'xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" ' +
'xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"> ' +
'<soap:Header> ' +
'<t:RequestServerVersion Version="Exchange2013" xmlns="http://schemas.microsoft.com/exchange/services/2006/types" soap:mustUnderstand="0" /> ' +
'</soap:Header> ' +
'<soap:Body> ' +
'<MoveItem xmlns="http://schemas.microsoft.com/exchange/services/2006/messages" ' +
'xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"> ' +
'<ToFolderId> ' +
'<t:DistinguishedFolderId Id="deleteditems"/> ' +
'</ToFolderId> ' +
'<ItemIds> ' +
'<t:ItemId Id="' + id + '" ChangeKey="' + changeKey + '"/> ' +
'</ItemIds> ' +
'</MoveItem> ' +
'</soap:Body> ' +
'</soap:Envelope> ';
return result;
}
I'm using firebase to get this data,
I'd like to add href tags to message.userName output
$('#winners').text('Winner:' + ' ' + message.userName + ' ' + ' '+ 'score:' + ' ' + message.score + ' ' + ' '+ 'Start time:' + ' ' + message.startTime + ' ' + ' '+ 'End time:' + '' + message.endTime );
I've tried
$('#winners').text('Winner:' + ' ' + '<a href=\"scoreTracker.php?id='+message.userID +'\"> + ' message.userName + ' ' + ' '+ 'score:' + ' ' + message.score + ' ' + ' '+ 'Start time:'
+ ' ' + message.startTime + ' ' + ' '+ 'End time:' + '' + message.endTime + '<\a>' );
To avoid XSS attacks (among other weird problems), append an anchor element and set its text. This means you don't have to worry about escaping anything.
$('#winners').append([
'Winner: ',
$('<a>')
.attr('href', 'scoreTracker.php?id=' + encodeURIComponent(message.userId))
.text(
message.userName + ' score: ' + message.score + ' Start time: ' + message.startTime + ' End time: ' + message.endTime
)
]);
If your HTML gets much more complicated, might I suggest a JavaScript template engine? I use Swig for most projects, but there are many choices.
you have to use append() , or html()
$('#winners').append('Winner:' + ' ' + message.userName + ' ' + ' '+ 'score:' + ' ' + message.score + ' ' + ' '+ 'Start time:' + ' ' + message.startTime + ' ' + ' '+ 'End time:' + '' + message.endTime );
this may help you to understand better :
http://api.jquery.com/category/manipulation/dom-insertion-inside/
Both #Brad and #ProllyGeek are correct -- but #Brad's solution is best given the potential risk of XSS attacks. Here is his code, just cleaned up a bit for better readability. :)
$('#winners').append([
'Winner: ',
$('<a />')
.attr('href', 'scoreTracker.php?id=' + encodeURIComponent(message.userId)
.text(message.userName + ' score: ' + message.score + ' Start time: ' + message.startTime + ' End time: ' + message.endTime)
]);
Hope this helps!
I've created a universal header dynamically that contains the date and time. Currently it acts and looks perfectly fine, but as soon as I remove the document.write('.') it disappears. It seems that I need any sort of write there in order for the dateDiv to appear, the '.' is just a random character used to fill the space.
//write date/time to div
var dateDiv = document.createElement('div');
dateDiv.innerHTML = '<p>' + d_names[curr_day] + ', ' + m_names[curr_month] + ' ' + curr_date + ', ' + curr_year + ' | ' + '<strong>' + curr_hour + ':' + curr_min + ' ' + a_p + '</strong>' + '</p>';
dateDiv.id = 'dateTime';
//dateDiv disappears without a document.write() before being appended to the body. need to fix
document.write('.');
document.body.appendChild(dateDiv);
I haven't been able to find an answer to this yet, anyone see the problem?
As loganfsmyth is implying its likely that your code is executed, when the document is not fully loaded. Try:
window.onload = function(){
//write date/time to div
var dateDiv = document.createElement('div');
dateDiv.innerHTML = '<p>' + d_names[curr_day] + ', ' + m_names[curr_month] + ' ' + curr_date + ', ' + curr_year + ' | ' + '<strong>' + curr_hour + ':' + curr_min + ' ' + a_p + '</strong>' + '</p>';
dateDiv.id = 'dateTime';
document.body.appendChild(dateDiv);
};
Edit:
See for example http://javascript.about.com/library/blonload.htm