While Mail Apps can use Ajax and SharePoint has REST endpoints this will not work because it violates Cross Site Security
The Solution: use a Generic Handler
Lets start by creating a new project in Visual Studio.
Let's call it "MyNewMailApp".
Your new project will open to “Home.html”
Let’s add a div tag to hold the data returned from our AJAX call. We’ll get to that later.
<div id="content-main">
<div class="padding">
. . .
</div>
<div id="output" class="padding"></div>
</div>
We will need to add a handler first. Select the “MyNewMailAppWeb” project in the Solution Explorer
“Ctrl-Shift-A” to add a new item and select Web > General > Generic Handler
Name it “GetSharePointSites”. The name should be specific and appropriate.
Now we need to give our app a way to find it.
Open the Web.Config file and update it as shown (in bold)
<?xml version="1.0" encoding="utf-8"?>
<!--
For more information on how to configure your ASP.NET application, please visit
http://go.microsoft.com/fwlink/?LinkId=169433
-->
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
</system.web>
<system.webServer>
<handlers>
<!-- handlers -->
<add
name="GetSharePointSites"
verb="*"
path="getsites"
type="MyNewMailAppWeb.GetSharePointSites"/>
</handlers>
</system.webServer>
</configuration>
Notice the “path” property. That will be the request endpoint for our Ajax call.
Now we need to add the references for communicating with O365.
Right-Click “MyNewMailAppWeb” in the Solution Explorer.
And click Add > Connected service
Click “Register your App”
Set the permissions on “Mail” and “Sites” to “Read”.
Next add references for Microsoft.SharePoint.Client and Microsoft.SharePoint.Client.Runtime both of them Version 15 .
Now that we have everything set, let’s get to the interesting part
Open GetSharePointSites.ashx
Replace the contents of
public void ProcessRequest(HttpContext context)
{
. . .
}
With
string SP_URL = "https://XXXXXXXX.sharepoint.com "; //Use your Site Collection URL
string SP_USER = "XXXXXX@XXXXXXXXX.com";
string SP_PWD = "XXXXXXXXX";
SecureString passWord = new SecureString();
foreach (char c in SP_PWD.ToCharArray()) passWord.AppendChar(c);
using (ClientContext clientContext = new ClientContext(SP_URL))
{
clientContext.Credentials = new SharePointOnlineCredentials(SP_USER, passWord);
if (clientContext != null)
{
try
{
clientContext.Load(clientContext.Web);
clientContext.ExecuteQuery();
clientContext.Load(clientContext.Web.Webs);
clientContext.ExecuteQuery();
if (clientContext.Web.Webs.AreItemsAvailable)
{
// Include top level site
string lists = clientContext.Web.Title;
// Loop through sub sites
foreach (var item in clientContext.Web.Webs)
{
lists += ", ";
lists += item.Title;
}
context.Response.Write(lists);
}
}
catch (Exception Ex)
{
context.Response.Write(Ex.Data.ToString());
}
}
}
This will write a comma separated list of site titles that our handler will return to our Ajax request.
NOTE: in the real world we would not hard code our credentials.
Now let’s open Home.js

Add a new function called getSites after “Office.initialize” and call it after “app.initialize”
// The Office initialize function must be run each time a new page is loaded
Office.initialize = function (reason) {
$(document).ready(function () {
app.initialize();
getSites();
});
};
//Displays available sites (Webs) in comma sepoarated list
function getSites() {
$.ajax({
url: '/getsites',
success: function (data) {
$('#output').append("<b style='color:green'>success! </b>" + data)
},
error: function (data) {
$('#output').append("<b style='color:red'>error!!! </b>" + data)
}
});
}
Now when we click Start (F5) , select and email and click the “MyNewMailApp” button, we will see a list of available sites in our site collection.