December 8, 2016

How to send an Email having HTML formatted Body through SharePoint Add-in

Scenario: 
While working with SharePoint Add-ins (SharePoint Hosted App), there was requirement to send an Email to users. We can do it through REST API with AJAX call in SharePoint but my concern was how I can send an email with HTML formatted body. 

Remember, The recipients users should be valid SharePoint Users. Emails cannot be sent to non-SharePoint users and external users.

Solution: Here is how I achieved it !
We have to include "AdditionalHeaders" in the mailObject which is required to specify the content type of the email, here is HTML. Without using this header, the email will be sent as a plain text, and the HTML formatting will be ignored.

function sendEMail(toList, subject, mailContent) {
    appweburl = decodeURIComponent(getQueryStringParameter('SPAppWebUrl'));
var restUrl = appweburl + "/_api/SP.Utilities.Utility.SendEmail",
restHeaders = { "Accept": "application/json;odata=verbose", "X-RequestDigest": $("#__REQUESTDIGEST").val(), "Content-Type": "application/json;odata=verbose" }, mailObject = { 'properties': { '__metadata': { 'type': 'SP.Utilities.EmailProperties' }, 'To': { 'results': toList }, 'Subject': subject, 'Body': mailContent, "AdditionalHeaders": { "__metadata":{ "type": "Collection(SP.KeyValue)" }, "results": [ { "__metadata": { "type": 'SP.KeyValue' }, "Key": "content-type", "Value": 'text/html', "ValueType": "Edm.String" } ] }
} }; return $.ajax({ contentType: "application/json", url: restUrl, type: "POST", data: JSON.stringify(mailObject), headers: restHeaders }); }
The above method can be called from SharePoint Add-in or Client Side code as shown below.
//An array of valid SharePoint Users, External users & emails are not supported.
var toUserList = [user1@email.com,
user2@email.com]
//Subject of the Email.
var mailSubject = "Download documents";
//HTML formatted Email Body.
var mailContent = "<h3>Here are all documents</h3><p>Links</p><div>document 1</div>";
sendEMail(toUserList, mailSubject , mailContent).done(function (response) {
    console.log("E-Mail Sent successfully.");
}).fail(function () {
    console.error("Error while sending an E-Mail.");
});
 
Hope this will help!

If you have any questions you can reach out our SharePoint Consulting team here.

November 25, 2016

Wrangling Large Data in Python (Part 1)

Present Day (TL;DR)

Before you go ahead and peek at the answer before understanding how it came about, I urge you to read the backstory and then come back to this section. By the way, what I will show you below is just like 30% of the answer. You can fill in the rest as per your use case.

You make a skeleton like so:

file_name = "folder/largefile.dat"  
nrows, frames = 0, []
for chunk in pd.read_csv(file_name, sep = "|", chunksize = 2500000, usecols = ["Col1""Col2"]):
    try:
        frames.append(chunk[chunk.Col1.isin(range(10))])
        nrows += chunk.shape[0]
        print("%d rows processed." % nrows)
    except Exception, e:
        print(e)

The place of interest is the line in bold.
I am merely building a list of data frames by chunk based on the condition that Col1 has values between 0 and 9 inclusive. But you can do a lot of things over there.
Here’s a hint: Create a function where you just take inputs such as the file name, columns of interest, and, most importantly, the function you want to apply to each chunk. Maybe you do not want to extract records. Maybe you want to build count tables, apply transformations, and about a million other things. Good news is: the limit to what you can do is your creativity.
One issue I faced is that when there is an “EOF character found” exception, the skiprows argument does not skip that record. It just stops the iterator and no exceptions are thrown.
My immediate idea for next steps is to try parallelizing this relatively snail-paced version that serially processes the file chunk by chunk.

Early in November 2016 (The month Trump became US President)

The day started like any other day. I came to the office, fired up my machine, and went to fetch my customary cup of java.

This was the day when everything changed. My faithful Jupyter Notebook environment was inundated with super-massive delimiter-separated files upward of 10 GB in size. Suddenly, 30 GB of RAM was not enough. The application stuttered. MemoryError exceptions were everywhere.
It was a welcome challenge to work with such large files without immediately resorting to Spark or such.

I wrote a simple first version that used nrows and skiprows arguments to manually iterate through chunks of the file. This version basically used a loop counter variable that I multiplied by a chosen chunk size. Then I’d manually set the values as nrows = <chunk size> and skiprows = i * <chunk size>. One exercise for the reader is to write this “manual” version.

There was nothing wrong with how the above way worked. But why not use something built-in and Pythonic? For now, the first way, which uses the chunksize argument, works well, and we use it for anything we do with large files.

In the next part of this post, we will discuss performance comparison. We will also begin considering more optimal ways of working with very large files including parallelism.

Watch this space for other posts and articles! If you have any questions you can reach out our team here.

November 23, 2016

Default Print button in SSRS Report is not showing/working in Chrome and Firefox browsers

Scenario
SSRS toolbox provides Print functionality. But it's browser dependent. It works fine only with Internet Explorer browser, not compatible with Firefox and Chrome browsers.

Resolution
To achieve this, we've to use custom Print button and JavaScript code which executes on button click.

HTML code for Print button and Report viewer:
 <asp:Button runat="server" CssClass="btn-addschedule-bot" Style="margin-left: 10px;" ID="btnPrint" CausesValidation="true" ValidationGroup="vgSubmit" OnClientClick="printReportClick();" Text="Print Report" />  
 <div style="border: 1px solid #A7B0E8; margin: 0px 10px; padding: 5px; float: left;">  
 <rsweb:ReportViewer ID="rptViewer" runat="server" Height="500px" Style="-ms-overflow-y: scroll" Width="1100px" ShowToolBar="False" ShowParameterPrompts="False" ShowCredentialPrompts="False"></rsweb:ReportViewer>  
 </div>  

JavaScript Code to print a report in Chrome and Firefox:
 <script type="text/javascript">  
     function printReport(report_ID) {  
       var rv1 = $('#' + report_ID);  
       var iDoc = rv1.parents('html');  
       // Reading the report styles  
       var styles = iDoc.find("head style[id$='ReportControl_styles']").html();  
       if ((styles == undefined) || (styles == '')) {  
         iDoc.find('head script').each(function () {  
           var cnt = $(this).html();  
           var p1 = cnt.indexOf('ReportStyles":"');  
           if (p1 > 0) {  
             p1 += 15;  
             var p2 = cnt.indexOf('"', p1);  
             styles = cnt.substr(p1, p2 - p1);  
           }  
         });  
       }  
       if (styles == '') { alert("Cannot generate styles, Displaying without styles.."); }  
       styles = '<style type="text/css">' + styles + "</style>";  
       //--- Reading the report html  
       var table = rv1.find("div[id$='_oReportDiv']");  
       if (table == undefined) {  
         alert("Report source not found.");  
         return;  
       }  
       //-- Generating a copy of the report in a new window  
       var docType = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">';  
       var docCnt = styles + table.parent().html();  
       var docHead = '<head><title>Printing ...</title><style>body{margin:5;padding:0;}</style></head>';  
       var winAttr = "location=yes, statusbar=no, directories=no, menubar=no, titlebar=no, toolbar=no, dependent=no, width=720, height=600, resizable=yes, screenX=200, screenY=200, personalbar=no, scrollbars=yes";;  
       var newWin = window.open("", "_blank", winAttr);  
       writeDoc = newWin.document;  
       writeDoc.open();  
       writeDoc.write(docType + '<html>' + docHead + '<body onload="window.print();">' + docCnt + '</body></html>');  
       writeDoc.close();  
       // The print event will fire as soon as the window loads  
       newWin.focus();  
       // uncomment to autoclose the preview window when printing is confirmed or canceled.  
       // newWin.close();  
     };  
     function printReportClick() {  
       printReport('<%=rptViewer.ClientID %>');  
     }  
   </script>  

Print Preview in Chrome browser:



I hope this will help you out to make print functionality working in Chrome and Firefox.

If you have any questions you can reach out our SharePoint Consulting team here.