How get the current user's own email address or check entered, using Exchange Web Services (EWS)? - exchangewebservices

I have to work with external Exchange server. How can I get the own email address or check address entered by the user (that he introduced exactly own address), using EWS?
Email address is not the same as username.

The best solution at this moment.
You can use ConvertId with a generic address and Exchange will then return the PrimarySMTP for that mailbox eg.
Folder Inbox = Folder.Bind(service, WellKnownFolderName.Inbox);
AlternateId aiAlternateid = new AlternateId(IdFormat.EwsId, Inbox.Id.UniqueId, "mailbox#domain.com");
AlternateIdBase aiResponse = service.ConvertId(aiAlternateid, IdFormat.EwsId);
Console.WriteLine(((AlternateId)aiResponse).Mailbox);

You might have some luck with the method ResolveName. Using this method you can search the Global Address List for the user. And by using a simple if else to see if any results were returned. This method does resolve ambiguous names so be sure to check the result carefully
Example:
NameResolutionCollection coll = service.ResolveName("Johnson", folders, ResolveNameSearchLocation.DirectoryOnly, false);
foreach (NameResolution nameRes in coll)
{
Console.WriteLine("Contact name: " + nameRes.Mailbox.Name);
Console.WriteLine("Contact e-mail address: " + nameRes.Mailbox.Address);
Console.WriteLine("Mailbox type: " + nameRes.Mailbox.MailboxType);
}
If you want to read more about it: https://msdn.microsoft.com/en-us/library/microsoft.exchange.webservices.data.exchangeservice.resolvename(v=exchg.80).aspx

Based on iCode4U's Answer, if your service uses default credentials (from the logged user), then this might get what you need:
String address = service.ResolveName(Environment.UserName)(0).Mailbox.Address;
EDIT: If one can't trust the uniqueness of the results brought by the query above, then it is better to use something like this (this would work in my organization, where usernames are also email identifiers, but each one must tweak it to fit his own scenario):
string address = Service.ResolveName(Environment.UserName).Select(
a => a.Mailbox.Address).FirstOrDefault(
b => b.StartsWith(Environment.UserName + "#",
StringComparison.InvariantCultureIgnoreCase));

We use this function loaded in the user PowerShell profile.
Function CurrentUserPrimarySmtpAddress()
{
<#
.SYSNOPSIS
Attempt to retrieve the current user's primary SMTP address.
.DESCRIPTION
Attempt to retrieve the current user's primary SMTP address.
.NOTES
Author: David Barrett
Date Created: 08NOV2016
.LINK
https://gallery.technet.microsoft.com/office/PowerShellEWS-Update-items-48c3dcfc
.EXAMPLE
$PrimarySmtpAddress = CurrentUserPrimarySmtpAddress
#>
$searcher = [adsisearcher]"(samaccountname=$env:USERNAME)"
$result = $searcher.FindOne()
if ($result -ne $null)
{
return $result.Properties["mail"]
}
return $null
}

Related

Get email message from Exchange using EWS Tracking Log Message ID or the InternalMessageID

I'm developing an application that tracks exchange email messages in our company.
We where able to get info out from the tracking log, but in the log -by design- there is no subject or body message.
So the next step for us was using EWS to get the message detail when needed.
The question is that in the tracking log we find to IDs :
MessageId in format "F533E7F015A2E24F8D8ABFE2587117C601EDF245#blstex02.subdomain.domain.com"
and
InternalMessageId in format "5840818"
If in EWS we use this id to find the message by id we always get an "Id is malformed." exception.
Here is the code we use:
public static EmailMessage GetEmailById(string uNameToImpersonate, string StringItemId)
{
return EmailMessage.Bind(GetService(uNameToImpersonate), new ItemId(StringItemId));
}
I'm a newbie to EWS so maybe I'm missing something really easy...
Thanks for your help
You can only bind to a Message using the EWSId see https://msdn.microsoft.com/en-us/library/office/dn605828(v=exchg.150).aspx for a more detailed discussion.For the InternetId you will need to search for messages with that particular Id using the findItem operation eg something like
ItemView ivew = new ItemView(1);
service.TraceEnabled = true;
ExtendedPropertyDefinition PidTagInternetMessageId = new ExtendedPropertyDefinition(4149, MapiPropertyType.String);
SearchFilter sf = new SearchFilter.IsEqualTo(PidTagInternetMessageId, "F533E7F015A2E24F8D8ABFE2587117C601EDF245#blstex02.subdomain.domain.com");
FindItemsResults<Item> iCol = service.FindItems(WellKnownFolderName.Inbox, sf, ivew);
foreach (Item item in iCol.Items)
{
Console.WriteLine(item.Subject);
}

Query Google Admin Directory users for partial name match

I'm trying to do two things:
Query AdminDirectory.Users.list by name field to return a list of anyone whose name matches a given string (even partially)
If possible, prevent the email address field from being included in the search
For example, "donald" should return data for the users Donald Duck, Donald Trump, and Ronald McDonald. If someone searched for "onald", that should work too.
The below sort of works. In the "donald" scenario, it would return only Donald Duck's data. For some reason it won't return more than one user.
function processForm(formObject) { // formObject comes from form on front end
var textSearchObject = formObject.textSearch; // "donald"
var userList = AdminDirectory.Users.list({
domain: 'somedomain.com',
query: "name:'" + textSearchObject + "'",
viewType: 'domain_public',
projection: 'full'
}).users;
return userList;
}
I know, query: "name:'" + textSearchObject + "'" looks very strange and most people would just use query: textSearchObject. The problem is that this searches email addresses - I need to avoid this if possible.
You're limited to "starts with" searching e.g. Donald* but you can search just the givenName, familyName or the combined name (fullName). Full documentation is here: https://developers.google.com/admin-sdk/directory/v1/guides/search-users

Sequelize findAll query returning incorrect results

I'm using Passport, Nodemailer, Sequelize, and Express to handle verification of user accounts who have signed up via email to the app.
To test this feature, I use Mailinator accounts to sign up, and send the email (along with a query string containing the user email and a uniquely-determined verification code) to the specified Mailinator address using Nodemailer. I then open the email in Nodemailer, click on the verification link, which updates the verification flag in the database and verifies the user.
This process works as I expect it to for exactly one user who signs up via email. When a second user signs up, the verification email is sent just as before with the username and unique verification codes in the query string, but this time, multiple users are being returned from the User.findAll query through Sequelize when the link is clicked. My query is intended to findAll possible matches of both email addresses and verification codes (since each user can only sign on with one email address and verification codes are unique), but for some reason the query is returning all matches from that query.
Here is some code for reference:
/* Sending the emails */
emails.sendActivationEmail = function(user){
const qso = {username: user.username, activationCode: user.activationCode};
const qs = querystring.stringify(qso);
const from = new helper.Email(<myEmailAddress#email.com>);
const to = new helper.Email(user.username);
const subject = 'Welcome to My Site!';
const content = new helper.Content('text/html', "<p> Thanks for signing up " +
"for our psych study, please <a href=\"http://localhost:7000/users/validate/account?" +
qs + "\">confirm your email</a></p>");
const mail = new helper.Mail(from, subject, to, content);
sendMail(mail); //invokes SendGrid mail helper function
}
/* Function invoked when user clicks on verification link in email */
emails.validateUserAccount = function(req, res){
const url = parseUrl(req.url);
const query = querystring.parse(url.query);
db.User.findAll({where: query}).then(function(matches){
if(matches.length !== 1){
res.send('error: multiple users found');
}
else{
db.User.update({
isVerified : true
},
{
where: {
username: matches[0].username
}
});
req.session.user = matches[0];
res.redirect('/');
}
}).catch(function(err){
console.error(err);
res.send(err);
});
}
Console statements in the validateUserAccount() function reveal that the query is exactly as I expect ({username: <emailAddress>, activationCode: <uniqueCode>}). However, console.log statements made in the first line after the findAll query is executed reveal that all users are being returned from the query, which should be impossible if the WHERE query is being passed in correctly, which it looks like it is from the logged statements. Why is User.findAll returning incorrect results from my query?
The problem here is that you are using the return value of querystring.parse()
As denoted in the Node docs:
Note: The object returned by the querystring.parse() method does not prototypically extend from the JavaScript Object. This means that the typical Object methods such as obj.toString(), obj.hasOwnProperty(), and others are not defined and will not work.
It's likely the where clause expects an actual JS Object.
Further, as #doublesharp mentioned, you probably want to be fetching one row and validating it, as opposed to findAlling the rows and then filtering through. Also, you should take advantage of callbacks. You're writing blocking code right now.

Username in WebTokenRequestResult is empty

in a Windows 10 UWP I try use WebAuthenticationCoreManager.RequestTokenAsync to get the result from a login with a Microsoft account.
I get a WebTokenRequestResult with Success. ResponseData[0] contains a WebAccount with an ID - but the UserName is empty.
The scope of the call is wl.basic - so I should get a lot of information...
I'm not sure how to retrieve extra information - and for the current test the Username would be OK.
I checked out the universal samples - and there I found a snippet which tries to do what I'm trying - an output of webTokenRequestResult.ResponseData[0].WebAccount.UserName.
By the way - the example output is also empty.
Is this a bug - or what do I (and the MS in the samples) have to do to get the users profile data (or at least the Username)?
According to the documentation (https://learn.microsoft.com/en-us/windows/uwp/security/web-account-manager), you have to make a specific REST API call to retrieve it:
var restApi = new Uri(#"https://apis.live.net/v5.0/me?access_token=" + result.ResponseData[0].Token);
using (var client = new HttpClient())
{
var infoResult = await client.GetAsync(restApi);
string content = await infoResult.Content.ReadAsStringAsync();
var jsonObject = JsonObject.Parse(content);
string id = jsonObject["id"].GetString();
string name = jsonObject["name"].GetString();
}
As to why the WebAccount property doesn't get set... shrugs
And FYI, the "id" returned here is entirely different from the WebAccount.Id property returned with the authentication request.

EWS Managed - Is it possible to get full "From" details using "FindItems"?

I'm using the Exchange Web Services Managed API to search a message folder using FindItems. The code I'm using is this:
var search = new SearchFilter.ContainsSubstring(
ItemSchema.Subject,
"subject I want");
ItemView searchView = new ItemView(9999);
searchView.PropertySet = new PropertySet(
BasePropertySet.IdOnly,
ItemSchema.Subject,
ItemSchema.DateTimeReceived,
EmailMessageSchema.From);
searchView.OrderBy.Add(
ItemSchema.DateTimeReceived,
SortDirection.Descending);
searchView.Traversal = ItemTraversal.Shallow;
var searchResults = _service.FindItems(
folderToSearch.Id,
search,
searchView);
The search works fine, and the properties I've specified in the searchView.PropertySet do get returned. The problem is that it doesn't return all of the details of From.
I iterate searchResults, and cast the items to type EmailMessage or PostItem as appropriate, to access the From property, which returns an EmailAddress object. On that object, the Name property is set, but Address is null.
If I then bind the item, like:
var boundItem = Item.Bind(_service, message.Id);
var boundItemEmail = boundItem as EmailMessage;
Then boundItemEmail.From.Address is not null, it returns the senders email address.
The trouble is, binding a message can be a rather time-consuming process, compared to the much faster FindItems operation.
You should be able to use the LoadPropertiesForItems method to get the From property, it's faster than binding to individual messages.