Why is it not possible to delete appointments in Exchange - exchangewebservices

I'm setting up a two way synchronization service for Appointments between Exchange and another business application. Because there was an old service before mine, I want to delete all the old appointments in Exchange but this is not possible with all appointments.
Everytime I debug, the appointments I can delete have appointment.Organizer.RoutingType filled with "SMTP" and appointment.Organizer.Address is filled with the e-Mail Address. The other ones have appointment.Organizer.RoutingType filled with "EX" and appointment.Organizer.Addresswith something like that:
/O=HOSTING/OU=EXCHANGE ADMINISTRATIVE GROUP FYDIBOHF23SYZLT)/CN=RECIPIENTS/CN=E373428996
do
{
itemChangeCollection = service.SyncFolderItems(new FolderId(WellKnownFolderName.Calendar), propertySet, null, 512, SyncFolderItemsScope.NormalItems, syncState);
foreach (ItemChange itemChange in itemChangeCollection)
{
try
{
if (itemChange.ChangeType != ChangeType.Delete)
{
Appointment app = Appointment.Bind(service, itemChange.ItemId, propertySet);
app.Delete(DeleteMode.MoveToDeletedItems);
}
}
catch (Exception ex)
{
}
}
syncState = itemChangeCollection.SyncState;
} while (itemChangeCollection.MoreChangesAvailable);
The error which is coming in the delete line is the following
Microsoft.Exchange.WebServices.Data.ServiceResponseException: 'The user account which was used to submit this request does not have the right to send mail on behalf of the specified sending account.'
The problem is not only the not possible delete, but also I need the E-Mail address of the organizer in my sync logic. Anybody here who knows why sometimes there is SMTP and sometimes EX?

EWS is attempting to send meeting cancellations for the specified appointment first and apparently the account you are using is not allowed to send on behalf of that mailbox. Try to cancel the meetign first: https://learn.microsoft.com/en-us/exchange/client-developer/exchange-web-services/how-to-delete-appointments-and-cancel-meetings-by-using-ews-in-exchange

Related

Trying to make script only send a message to teams if specific value returned

I can login, get the API token from the server, and return the values I'm looking for. What I haven't been able to do is make the script write to the host only if the value returned is NOT "Primary".
I'm not quite to sending an alert to MS Teams yet as I'm building this modular as I go.
Right now, the code always writes "fail" to the host regardless of the value I set. I had originally put a simple If -not match statement within the CAStatus function, but I don't want to build my alert function within the function I'm using to retrieve server status
#Use login token to pull CA system status
Function CAStatus {
#URL and logon token in header
$system_summary_uri ="https://website.com"
$header_parameters = #{"Authorization" = CALogon}
#Get Summary info from primary CA server and only return its role
(Primary or DR)
$summary_query = Invoke-RestMethod -Uri $system_summary_uri -Method Get -
Headers $header_parameters -ContentType "application/json"
$summary_result = $summary_query.Vaults.Role[0]
return $summary_result
}
#Report if primary server fails
Function Notify {
if (CAStatus -eq "dr") {
Write-Host "fail"
}
}
castatus
I expect output of "fail" only when the value returned by the API call to CAStatus is "DR". Otherwise I want it to do nothing.
Right now, when I run CAStatus, I get the value "Primary" returned, which is correct since the server is currently in the primary role. There should be nothing output to the host since CAStatus does not equal "dr", but it is outputting "fail" anyway.

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);
}

How can I send a POST request without sending an auto incrementing primary key in express

I am writing a simple API which I have been testing using Postman. I have an auto incrementing primary key (CustomerTypeID) for my "customer_type" table stored in MySQL. For practical reasons I need to be able to create records in this table without sending a CustomerTypeID. When I send the following POST request using Postman:
{
"CustomerType": "testing"
}
The updated table shows a new row with CustomerTypeID of 2 and a CustomerType of NULL.
Below is a snippet of code in my Express API which shows this specific query and how the routing for this POST request works.
var db = require('../dbconnection.js');
var CustomerType = {
addCustomerType:function(CustomerType,callback) {
return db.query("INSERT INTO customer_type (CustomerType) VALUES (?)", [CustomerType.CustomerType], callback);
}
};
module.exports = CustomerType;
I know that I could change the query to say
INSERT INTO customer_type (CustomerTypeID, CustomerType) VALUES (?,?);
and that would fill both columns. But, I do not know how to leave out the CustomerTypeID column as it will be a number that the end user will have no way of knowing.
It turns out that the syntax for the last query I gave is correct. I used the same POST request as before:
{
"CustomerType": "testing"
}
And by using the SQL query that includes CustomerTypeID, MySQL knew to just increment the value of CustomerTypeID since it was not given a value in the POST request. When I ran the same POST again with this query I received a new row with both a CustomerTypeID and a CustomerType.

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.

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

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
}