I have an excel spreadsheet containing the expiration dates for all certifications for each member of my team. As the expiration approaches, the cell automatically color shifts based on the remaining validity of the certification.
What I am looking to do is send an email notification when the certification is expiring in 90 days or less.
function sendEmail() {
// EMAIL Check & Date
// Fetch Cert Dates & Employees
var CertExpiration = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1").getRange(4,3,11,9); //All Cert Dates on Sheet
var CertDate = CertExpiration.getValue(); // Get Certificate Date as a value
var Employee = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1").getRange(4,2,9,1); //Retrieve list of employee Names
var EmployeeName = Employee.getValue(); // Set variable for email notification
var Today = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1").getRange(2,2,1,1); // Sets Today to Today() on sheet
// Check Cert Expiration
if (CertDate - Today < 90);
{
// Fetch the email address
var emailAddress = 'Example#Example.com';
// Send Alert Email.
var message = 'Certificate for ' + EmployeeName + ' expiring soon'; //
var subject = 'CERT EXPIRING SOON | CV CERT TRACKING';
MailApp.sendEmail(emailAddress, subject, message);
}
}
I would like this email to contain a list of all EmployeeName that match the condition (CertDate - Today <90) if possible. Additionally, a method by which to prevent the email from being sent multiple times. Currently, the email sends successfully, but only contains the first referenced EmployeeName.
I'm guessing you need a loop function to go through all your data.
function sendEmail() {
const data = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1").getRange(4,2,11,9).getValues();
for (let i = 0; i< data.length ;i++){
//change the [i][0] the second number in [] to the actual index of your number column. If your column number is 5, then the index will be 4
//index start from 0.
const EmployeeName = data[i][0];
const CertDates = data[i].slice(1);
const Today = new Date()
//this arr will hold each cert date less than 90 days.
const arr = [];
for(let j=0; j<CertDates.length ;j++ ){
const CertDate = CertDates[j];
if(typeof(CertDate)== 'object' && Math.floor((CertDate - Today ) / (1000*60*60*24)) < 90){
console.log(CertDate)
arr.push(CertDate);
}
}
//if any emlpoyees has expire date less than 90 days. 1 or many. It will send email to employee name.
if(arr.length>0){
// Fetch the email address
var emailAddress = 'Example#Example.com';
// Send Alert Email.
var message = 'Certificate for ' + EmployeeName + ' expiring soon'; //
var subject = 'CERT EXPIRING SOON | CV CERT TRACKING';
MailApp.sendEmail(emailAddress, subject, message);
}
}
Related
I'm using a code that I've found for deleting bulk events from google calendar, based on values from google sheets (the code is in the google sheet script editor).
It's working when I'm using it on my personal calendar, but when I try to delte events from a google classroom calendar (which I'm its manager), I get the error message "TypeError: Cannot read property 'getEvents' of undefined". Do you have any idea why this is happening?
function delete_google_calendar()
{
var spreadsheet = SpreadsheetApp.getActiveSheet();
var startYear = spreadsheet.getRange("B67").getValue();
var startMonth = spreadsheet.getRange("F67").getValue();
var startDay = spreadsheet.getRange("H67").getValue();
var endYear = spreadsheet.getRange("B68").getValue();
var endMonth = spreadsheet.getRange("F68").getValue();
var endDay = spreadsheet.getRange("H68").getValue();
var fromDate = new Date(startYear,startMonth,startDay,0,0,0);
var toDate = new Date(endYear,endMonth,endDay,0,0,0);
var calendarId = "mandel-institute.org.il_classroom682af58e#group.calendar.google.com";
// First number: Year
//Second number: Month (January=0)
//Third number: Day
var calendar = CalendarApp.getCalendarsByName(calendarId)[0];
var events = calendar.getEvents(fromDate, toDate);
for(var i=0; i<events.length;i++){
var ev = events[i];
ev.deleteEvent();
}
}
Apps Script offers to methods for retrieving calendars: getCalendarsByName(name) and getCalendarById(id)
Thereby, since you have a caledar id available, you need to use the method getCalendarById(id):
var calendar = CalendarApp.getCalendarById(calendarId)
Since the id identifies a calendar unambiguously only one calendar (instead of an array) will be returned, so skip the [0].
I am new to Google Apps Script and learning javascript as I go about this project. Over the course of the introductory codelabs I noted the best practice to read all the data into an array with one command, perform operations, and then write it with one command.
I understood how to do this working with Google Sheets but how do I achieve this working with Google Calendar? I have come across a few links discussing batching with Google Calendar API and Advanced Google Services but I didn't understand how to make use of the information.
I basically hope to batch edit events instead of accessing Google Calendar repeatedly in a for loop.
function deleteMonth() {
// Set Date range to delete
var today = new Date();
var firstDay = new Date(today.getFullYear(), today.getMonth(), 1);
var lastDay = new Date(today.getFullYear(), today.getMonth() + 1, 0);
// read spreadsheet data and get User Info from ss
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var idSheet = spreadsheet.getSheetByName('User Info');
//Get users from sheet in array of objects with properties from column header in
//'User Info' (name, email, year, calName, calID, early, late)
var userInfo = getSheetData(idSheet);
var deletedNames = "";
for (i = 0; i < userInfo.length; i++) {
var calID = userInfo[i].calID;
// if we have calID proceed to delete events
if (calID) {
console.time("get events");
var calendar = CalendarApp.getCalendarById(calID);
var events = calendar.getEvents(firstDay, lastDay);
console.timeEnd("get events");
// Delete events and add deleted name to string
// deletedNames
for (i = 0; i < events.length; i++) {
console.time("delete event");
deletedNames += events[i].getTitle() + ", ";
events[i].deleteEvent();
console.timeEnd("delete event");
}
}
}
spreadsheet.toast("Deleted events: \n" + deletedNames);
}
Time output from console.time():
Other related links which sounded relevant:
Using advanced google services (apps script resource)
Google Developer blog?
I believe your goal as follows
You want to delete all events in a month for several calendars using the batch process with Google Apps Script.
You want to reduce the process cost of above process.
For this, how about this answer?
Issue and workaround:
Calendar API can process with the batch requests. The batch requests can run 100 requests by one API call and can process with the asynchronous process. By this, I think that the process cost can bereduced. But, in the current stage, unfortunately, several calendar IDs cannot be used in one batch. When the requests including several calendar IDs, an error of Cannot perform operations on different calendars in the same batch request. occurs. So in your case, all events in a month in one calendar ID can be deleted in one batch requests. It is required to request the number of calendar IDs. I would like to propose this as the current workaround.
By the way, as the modification point of your scrit, in your script, the variable i is used in 1st for loop and 2nd for loop. By this, all values of userInfo are not used. Please be careful this.
Sample script:
Before you run the script, please enable Calendar API at Advanced Google services.
function deleteMonth() {
var today = new Date();
var firstDay = new Date(today.getFullYear(), today.getMonth(), 1);
var lastDay = new Date(today.getFullYear(), today.getMonth() + 1, 0);
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var idSheet = spreadsheet.getSheetByName('User Info');
var userInfo = getSheetData(idSheet);
var deletedNames = "";
var requests = []; // For batch requests.
for (i = 0; i < userInfo.length; i++) {
var req = [];
var calID = userInfo[i].calID;
if (calID) {
var calendar = CalendarApp.getCalendarById(calID);
var events = calendar.getEvents(firstDay, lastDay);
for (j = 0; j < events.length; j++) {
deletedNames += events[j].getTitle() + ", ";
var e = events[j];
req.push({
method: "DELETE",
endpoint: `https://www.googleapis.com/calendar/v3/calendars/${calID}/events/${e.getId().replace("#google.com", "")}`,
});
}
}
requests.push(req);
}
// Run batch requests.
requests.forEach(req => {
const limit = 100;
const split = Math.ceil(req.length / limit);
const boundary = "xxxxxxxxxx";
for (let i = 0; i < split; i++) {
const object = {batchPath: "batch/calendar/v3", requests: req.splice(0, limit)};
const payload = object.requests.reduce((s, e, i) => s += "Content-Type: application/http\r\nContent-ID: " + i + "\r\n\r\n" + e.method + " " + e.endpoint + "\r\nContent-Type: application/json; charset=utf-8\r\n\r\n" + JSON.stringify(e.requestBody) + "\r\n--" + boundary + "\r\n", "--" + boundary + "\r\n");
const params = {method: "post", contentType: "multipart/mixed; boundary=" + boundary, payload: payload, headers: {Authorization: "Bearer " + ScriptApp.getOAuthToken()}, muteHttpExceptions: true};
var res = UrlFetchApp.fetch("https://www.googleapis.com/" + object.batchPath, params);
console.log(res.getContentText())
}
})
spreadsheet.toast("Deleted events: \n" + deletedNames);
}
Note:
Please use this script with V8.
References:
Advanced Google services
Sending Batch Requests
Events: delete
I have data from a questionnaire (20K rows) that I need to share with the store managers (report) of our shops (400 shops). I managed to write a script that sends a pdf of my sheet to a list of e-mail addresses. But I'm stuck on writing the loop for the filter, since I can't get the setVisibleValues(values) function to work for FilterCriteriaBuilder. The setHiddenValues(values) function works, but I can't figure out how to combine that with the loop.
Sample of my Google Sheet
See below for my current code:
/**
* Filtersheet by location
*/
function FilterSheet() {
var spreadsheet = SpreadsheetApp.getActive().getSheetByName('Data')
spreadsheet.getRange('F1').activate();
var criteria = SpreadsheetApp.newFilterCriteria()
.setHiddenValues(['Amsterdam, Rotterdam'])
.build();
spreadsheet.getFilter().setColumnFilterCriteria(6, criteria);
};
/**
* Send pdf of currentspreadsheet
*/
function SendPdf() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var spreadsheet = SpreadsheetApp.getActive().getSheetByName('Adres');
var blob = DriveApp.getFileById(ss.getId()).getAs("application/pdf");
blob.setName(ss.getName() + ".pdf");
var startRow = 2; // First row of data to process
var numRows = 2; // Number of rows to process
// Fetch the range of cells A2:B3
var dataRange = spreadsheet.getRange(startRow, 1, numRows, 2);
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (var i in data) {
var row = data[i];
var emailAddress = row[0]; // First column
var message = 'I hearby send you the overview of your data'
var subject = 'Overview of data';
MailApp.sendEmail(emailAddress, subject, message,{
attachments:[blob]});
}
}
getValues() returns the values of all range's cells no matter if they are shown or hidden.
Use a loop and isRowHiddenByFilter(rowPosition) to reap out all the filtered values. You could use Array.prototype.push to add the values to a new array or use Array.prototype.splice to modify the array holdin the values returned by getValues()
Related
How to use in Google Sheets setValue only for range of filtered rows (getRange for not hidden cells)?
I managemed to solve the problem.
This script takes a google spreadsheet with 2 sheets,one with Data and one with a combination EmailAdresses.
It sends a filtered list (filter column F) of sheet Data to the corresponding salon (location) in sheet Emailadresses (var mode email). Additionally, it has the option to "store" the pdf's in your google drive (var mode store)
*/
function construct() {
// settings:
//var mode = "store";
var mode = "email";
// get list of all salons and email
var salonList = SpreadsheetApp.getActive().getSheetByName('EmailAdressen');
// set endvar for loop
var endRow = salonList.getLastRow();
// loop trough the rows to get the Salon name and the corresponding email
for(i=1;i<=endRow;i++){
var salonName = salonList.getRange(i,2).getValue();
var email = salonList.getRange(i,1).getValue();
// create an array with all salons that should be hidden (we cant pick which one to show, so we have to go the other way around...)
var filterArray = [];
// create array with all salons to hide
for(c=1;c<=endRow;c++){
// get value from email list, check if it is not the current selected one and if so add it to the list to filter out
salonFilterName = salonList.getRange(c,2).getValue();
if(salonFilterName != salonName) {
filterArray.push(salonFilterName);
}
} // end for c
// filter the list with the array we just created
var spreadsheet = filterList(filterArray);
if(mode == "email"){
// export to PDF
var pdf = exportToPdf(spreadsheet);
// email to email address belonging to this salon
emailToAddress(email, pdf);
} // end if
if(mode == "store"){
StorePdf(spreadsheet, salonName);
}
} // end for i
return;
}
function filterList(salonNameArray) {
// select data sheet
var spreadsheet = SpreadsheetApp.getActive().getSheetByName('Data');
// first remove all existing filters to make sure we are on a clean sheet
if(spreadsheet.getFilter()){
spreadsheet.getFilter().remove();
}
// create the filter
spreadsheet.getRange('F:F').createFilter();
// set criteria for filter with array passed from construct
var criteria = SpreadsheetApp.newFilterCriteria().setHiddenValues(salonNameArray).build();
// apply filter
spreadsheet.getFilter().setColumnFilterCriteria(6, criteria);
return spreadsheet;
}
function exportToPdf(ss) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var spreadsheet = SpreadsheetApp.getActive().getSheetByName('Data');
var blob = DriveApp.getFileById(ss.getId()).getAs("application/pdf");
blob.setName(ss.getName() + ".pdf");
return blob;
}
function StorePdf(ss, salonName) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var spreadsheet = SpreadsheetApp.getActive().getSheetByName('Data');
var blob = DriveApp.getFileById(ss.getId()).getBlob();
blob.setName(salonName + "_" + Utilities.formatDate(new Date(), "GMT+1", "ddMMyyyy")+".pdf");
DriveApp.createFile(blob);
return;
}
function emailToAddress(email, pdf) {
MailApp.sendEmail(email, 'Type here the subject', 'Type here the body',{
attachments:[pdf]});
return;
}
Full disclosure, I am in no way a programmer of any kind. My library was looking for an easier way for multiple locations to add events to the public calendar.
Eventually I stumbled upon this script which I was able to adapt for our needs. However, the one change they would like is to have the end time default to 2 hours later. For example, if an event starts at 1 then the end time automatically defaults to 3.
Can anyone show me what change in the script I need to make for that to happen? Here is the test form that we use to enter the dates. Right now the end time is entered manually but I'd imagine that would have to be removed, correct?
Any help in figuring this out would be greatly appreciated.
Thanks!
//insert your google calendar ID
var calendarId = "ID-FOR-TEST-CALENDAR";
//index (starting from 1) of each column in the sheet
var titleIndex = 2;
var descriptionIndex = 3;
var startDateIndex = 4;
var endDateIndex = 5;
var googleCalendarIndex = 6;
/*
find the row where the Google Calendar Event ID is blank or null
The data of this row will be used to create a new calendar event
*/
function findRow(sheet) {
var sheet = SpreadsheetApp.getActiveSheet();
var dataRange = sheet.getDataRange();
var values = dataRange.getValues();
for (var i = 0; i < values.length; i++) {
if(values[i][googleCalendarIndex-1]=="" || values[i][googleCalendarIndex-1]==null)
newEvent(i+1);
}
};
/*
get the data of the new row by calling getSheetData() and
create a new Calendar event by calling submitToGoogleCalendar()
*/
function newEvent(row){
var sheet = SpreadsheetApp.getActiveSheet();
var eventId = submitToGoogleCalendar(getSheetData(sheet,row),null)
if(eventId!=null)
sheet.getRange(row,googleCalendarIndex,1,1).setValue(eventId);
};
/*
Store the data of a row in an Array
*/
function getSheetData(sheet,row)
{
var data = new Array();
data.title=sheet.getRange(row,titleIndex,1,1).getValue();
data.description=sheet.getRange(row,descriptionIndex,1,1).getValue();
data.startDate = sheet.getRange(row,startDateIndex,1,1).getValue();
data.endDate = sheet.getRange(row,endDateIndex,1,1).getValue();
return data;
};
/*
if a cell is edited in the sheet, get all the data of the corresponding row and
create a new calendar event (after deleting the old event) by calling submitToGoogleCalendar()
*/
function dataChanged(event){
var sheet = SpreadsheetApp.getActiveSheet();
var row = event.range.getRow();
var eventId = sheet.getRange(row,googleCalendarIndex,1,1).getValue();
var eventId = submitToGoogleCalendar(getSheetData(sheet,row),eventId)
if(eventId!=null)
sheet.getRange(row,googleCalendarIndex,1,1).setValue(eventId);
};
/*
This function creates an event in the Google Calendar and returns the calendar event ID
which is stored in the last column of the sheet
*/
function submitToGoogleCalendar(sheetData,eventId) {
// some simple validations ;-)
if(sheetData.title == "" || sheetData.startDate == "" || sheetData.startDate == null)
return null;
var cal = CalendarApp.getCalendarById(calendarId);
var start = new Date(sheetData.startDate);
var end = new Date(sheetData.endDate);
// some simple date validations
if(start > end)
return null;
var event = null;
//if eventId is null (when called by newEvent()) create a new calendar event
if(eventId==null)
{
event = cal.createEvent(sheetData.title, start, end, {
description : sheetData.description,
});
return event.getId();
}
/*
else if the eventid is not null (when called by dataChanged()), delete the calendar event
and create a new event with the modified data by calling this function again
*/
else
{
event = cal.getEventSeriesById(eventId);
event.deleteEventSeries();
return submitToGoogleCalendar(sheetData,null);
}
return event.getId();
};
Without having tried it myself, I believe you could do it like this:
function submitToGoogleCalendar(sheetData,eventId) {
var cal = CalendarApp.getCalendarById(calendarId);
var start = new Date(sheetData.startDate);
var end = new Date(sheetData.endDate);
end.setHours(start.getHours() + 2);
...where the last line is the new line added to your original script.
To your question wether the end time should be removed, I would say yes, it should be removed.
all I need to do is to retrieve all contacts from Microsoft Exchange. I did some research and the best possible option for me should be to use EWS Managed API. I am using Visual Studio and C# programming leanguage.
I think I am able to connect to Office365 account, because I am able to send a message in a program to specific email. But I am not able to retrieve the contacts.
If I create a contact directly in source code, the contact will be created in Office365->People aplication. But I don't know why! I thought I was working with Exchange aplication.
Summarize:
Is there any possibility how to get all contacts from Office365->Admin->Exchange->Acceptencers->Contacts ?
Here is my code:
class Program
{
static void Main(string[] args)
{
// connecting to my Exchange account
ServicePointManager.ServerCertificateValidationCallback = CertificateValidationCallBack;
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2007_SP1);
service.Credentials = new WebCredentials("office365email#test.com", "password123");
/*
// debugging
service.TraceEnabled = true;
service.TraceFlags = TraceFlags.All;
*/
service.AutodiscoverUrl("office365email#test.com", RedirectionUrlValidationCallback);
// send a message works good
EmailMessage email = new EmailMessage(service);
email.ToRecipients.Add("matoskok1#gmail.com");
email.Subject = "HelloWorld";
email.Body = new MessageBody("Toto je testovaci mail");
email.Send();
// Create the contact creates a contact in Office365 -> People application..Don't know why there and not in Office365 -> Exchange
/*Contact contact = new Contact(service);
// Specify the name and how the contact should be filed.
contact.GivenName = "Brian";
contact.MiddleName = "David";
contact.Surname = "Johnson";
contact.FileAsMapping = FileAsMapping.SurnameCommaGivenName;
// Specify the company name.
contact.CompanyName = "Contoso";
// Specify the business, home, and car phone numbers.
contact.PhoneNumbers[PhoneNumberKey.BusinessPhone] = "425-555-0110";
contact.PhoneNumbers[PhoneNumberKey.HomePhone] = "425-555-0120";
contact.PhoneNumbers[PhoneNumberKey.CarPhone] = "425-555-0130";
// Specify two email addresses.
contact.EmailAddresses[EmailAddressKey.EmailAddress1] = new EmailAddress("brian_1#contoso.com");
contact.EmailAddresses[EmailAddressKey.EmailAddress2] = new EmailAddress("brian_2#contoso.com");
// Specify two IM addresses.
contact.ImAddresses[ImAddressKey.ImAddress1] = "brianIM1#contoso.com";
contact.ImAddresses[ImAddressKey.ImAddress2] = " brianIM2#contoso.com";
// Specify the home address.
PhysicalAddressEntry paEntry1 = new PhysicalAddressEntry();
paEntry1.Street = "123 Main Street";
paEntry1.City = "Seattle";
paEntry1.State = "WA";
paEntry1.PostalCode = "11111";
paEntry1.CountryOrRegion = "United States";
contact.PhysicalAddresses[PhysicalAddressKey.Home] = paEntry1;
// Specify the business address.
PhysicalAddressEntry paEntry2 = new PhysicalAddressEntry();
paEntry2.Street = "456 Corp Avenue";
paEntry2.City = "Seattle";
paEntry2.State = "WA";
paEntry2.PostalCode = "11111";
paEntry2.CountryOrRegion = "United States";
contact.PhysicalAddresses[PhysicalAddressKey.Business] = paEntry2;
// Save the contact.
contact.Save();
*/
// msdn.microsoft.com/en-us/library/office/jj220498(v=exchg.80).aspx
// Get the number of items in the Contacts folder.
ContactsFolder contactsfolder = ContactsFolder.Bind(service, WellKnownFolderName.Contacts);
Console.WriteLine(contactsfolder.TotalCount);
// Set the number of items to the number of items in the Contacts folder or 50, whichever is smaller.
int numItems = contactsfolder.TotalCount < 50 ? contactsfolder.TotalCount : 50;
// Instantiate the item view with the number of items to retrieve from the Contacts folder.
ItemView view = new ItemView(numItems);
// To keep the request smaller, request only the display name property.
view.PropertySet = new PropertySet(BasePropertySet.IdOnly, ContactSchema.DisplayName);
// Retrieve the items in the Contacts folder that have the properties that you selected.
FindItemsResults<Item> contactItems = service.FindItems(WellKnownFolderName.Contacts, view);
// Display the list of contacts.
foreach (Item item in contactItems)
{
if (item is Contact)
{
Contact contact1 = item as Contact;
Console.WriteLine(contact1.DisplayName);
}
}
Console.ReadLine();
} // end of Main() method
/*===========================================================================================================*/
private static bool CertificateValidationCallBack(
object sender,
System.Security.Cryptography.X509Certificates.X509Certificate certificate,
System.Security.Cryptography.X509Certificates.X509Chain chain,
System.Net.Security.SslPolicyErrors sslPolicyErrors)
{
// If the certificate is a valid, signed certificate, return true.
if (sslPolicyErrors == System.Net.Security.SslPolicyErrors.None)
{
return true;
}
// If there are errors in the certificate chain, look at each error to determine the cause.
if ((sslPolicyErrors & System.Net.Security.SslPolicyErrors.RemoteCertificateChainErrors) != 0)
{
if (chain != null && chain.ChainStatus != null)
{
foreach (System.Security.Cryptography.X509Certificates.X509ChainStatus status in chain.ChainStatus)
{
if ((certificate.Subject == certificate.Issuer) &&
(status.Status == System.Security.Cryptography.X509Certificates.X509ChainStatusFlags.UntrustedRoot))
{
// Self-signed certificates with an untrusted root are valid.
continue;
}
else
{
if (status.Status != System.Security.Cryptography.X509Certificates.X509ChainStatusFlags.NoError)
{
// If there are any other errors in the certificate chain, the certificate is invalid,
// so the method returns false.
return false;
}
}
}
}
// When processing reaches this line, the only errors in the certificate chain are
// untrusted root errors for self-signed certificates. These certificates are valid
// for default Exchange server installations, so return true.
return true;
}
else
{
// In all other cases, return false.
return false;
}
}
private static bool RedirectionUrlValidationCallback(string redirectionUrl)
{
// The default for the validation callback is to reject the URL.
bool result = false;
Uri redirectionUri = new Uri(redirectionUrl);
// Validate the contents of the redirection URL. In this simple validation
// callback, the redirection URL is considered valid if it is using HTTPS
// to encrypt the authentication credentials.
if (redirectionUri.Scheme == "https")
{
result = true;
}
return result;
}
}
seems like you are already doing a good job doing a FindItems() method.
In order to get all contacts all you need to add is a SearchFilter, in this case I'd recommend doing the Exists() filter as you can simply say Find All contacts with an id.
See my example below if you need an example of a Full Windows Application dealing with contacts see my github page github.com/rojobo
Dim oFilter As New SearchFilter.Exists(ItemSchema.Id)
Dim oResults As FindItemsResults(Of Item) = Nothing
Dim oContact As Contact
Dim blnMoreAvailable As Boolean = True
Dim intSearchOffset As Integer = 0
Dim oView As New ItemView(conMaxChangesReturned, intSearchOffset, OffsetBasePoint.Beginning)
oView.PropertySet = BasePropertySet.IdOnly
Do While blnMoreAvailable
oResults = pService.FindItems(WellKnownFolderName.Contacts, oFilter, oView)
blnMoreAvailable = oResults.MoreAvailable
If Not IsNothing(oResults) AndAlso oResults.Items.Count > 0 Then
For Each oExchangeItem As Item In oResults.Items
Dim oExchangeContactId As ItemId = oExchangeItem.Id
//do something else
Next
If blnMoreAvailable Then oView.Offset = oView.Offset + conMaxChangesReturned
End If
Loop
How to retrieve all contacts from Microsoft Exchange using EWS Managed API?
If your question is how to retrieve the Exchange Contacts using EWS, you're already done with it.
Office365->People is just the right app to manipulate your Exchange contacts. If you check out the People app URL, it's something similar to https://outlook.office365.com/owa/?realm=xxxxxx#exsvurl=1&ll-cc=1033&modurl=2, owa is the synonym for outlook web app.