Windows Azure worker role and SendGrid "Bad Key Path!" Error - azure

I'm trying to use SendGrid to send an email from an Azure worker role every time there are certain exceptions, but I can't get the email to send. I am using SendGridMail version 6.1.0.0 and SendGrid.SmtpApi version 1.3.1.0 which I installed via nuget and .Net 4.5. I am currently debugging locally with plans to deploy to Azure if i can get the emails to successfully send.
SendGridMessage myMessage = new SendGridMessage();
List<String> recipients = new List<String> { #"John Doe <johnd#outlook.com>", #"Peter Howe <perterhowe#gmail.com>" };
myMessage.AddTo(recipients);
myMessage.From = new MailAddress("myemail#test.com");
myMessage.Subject = "Error in Update";
myMessage.Text = "TESTING 123";
string username = XXXXXX;
string password = XXXXXXX;
// Create credentials, specifying your user name and password.
var credentials = new NetworkCredential(username, password);
// Create an Web transport for sending email.
var transportWeb = new Web(credentials);
// Send the email.
await transportWeb.DeliverAsync(myMessage);
As far as I can see I'm not getting any errors except when I debug and look at myMessage the Header has an error.
When I tried initializing a new empty header (var header = new Header();) I noticed there were still errors on that
To = 'header.To' threw an exception of type 'System.ArgumentException' Message = "Bad key path!"
Does anyone know what this means? Or if this could be causing the emails not to send?

The answer to your other question actually uses SendGrid:
Alerts for exceptions in an Azure worker role
There are three globalvariables:
public const string SmtpServerHost = "smtp.sendgrid.net";
public const string SmtpServerUserName = "[useridfromsendgrid#azure.com]";
public const string SmtpServerPassword = "[password from sendgrid]";
You actually do not need to use the SDK, just setup the account in Azure portal, and save your creds in your project.
You can send emails locally, but if you are on a work network, the firewall may block the emails from being sent. The code I posted I placed in an email service in my namespace.

It has be deployed to Azure to work. It won't work locally.

Related

Azure Bot channel error "There was an error sending this message to your bot: HTTP status code Unauthorized"

I'm getting Unauthorized error when try to send message from azure Bot channel to api. I have deployed azure app and Bot channel with pulumi. In azure application I have noticed that there is a warning in authentication section about Implicit Grant.
If I disable Implicit Grant setting from azure portal then Bot channel works fine. I'm creating azure application with default settings as per pulumi documentation but there is no option to remove this Implicit Grant settings
I have created Azure application and Bot channel with pulumi using this link
public static AzureAD.Application Create()
{
var name = "app-name";
var azureApp = new AzureAD.Application(name, new AzureAD.ApplicationArgs
{
Name = name
// Tried combinations of the following lines, but it makes no difference
//, Type = "native"
//, Oauth2AllowImplicitFlow = false
});
CreatePrincipal(azureApp);
return azureApp;
}
private static void CreatePrincipal(AzureAD.Application azureApp)
{
var name = "app-principal";
new AzureAD.ServicePrincipal(name, new AzureAD.ServicePrincipalArgs
{
ApplicationId = azureApp.ApplicationId
});
}
public static ChannelsRegistration Create(ResourceGroup resourceGroup, AzureAD.Application teamsBotAzureApp)
{
var channelName = "Channel";
var channel = new ChannelsRegistration(channelName, new ChannelsRegistrationArgs
{
Location = "global",
ResourceGroupName = resourceGroup.Name,
Sku = "F0",
MicrosoftAppId = teamsBotAzureApp.ApplicationId,
Endpoint = "https://azurefunction.com/api/BotMessagesHandler"
});
CreateChannel(resourceGroup, channel);
return channel;
}
In azure ad, the setting of Implicit Grant is controlled by the parameters in the Manifest(you can also set them in the UI, then they will be changed in the manifest), Access tokens corresponds to oauth2AllowImplicitFlow, ID tokens corresponds to oauth2AllowIdTokenImplicitFlow.
If you create the app with pulumi, you can set the Oauth2AllowImplicitFlow = false to disable the Access tokens, but looks there is no oauth2AllowIdTokenImplicitFlow in the pulumi inputs, so you could not disable the ID tokens via pulumi.
You could try the workarounds below.
1.From the warning, it says You should remove these settings or register the appropriate redirect URI. So you could try to create the app with a redirect URI(i.e. ReplyUrls ) with the code like below, see if it works without disabling the ID tokens.
ReplyUrls =
{
"https://replyurl",
}
2.If it is accepted, you could use the Microsoft Graph SDK to update the application after creating it. Set the enableIdTokenIssuance to false in implicitGrantSettings of web property, then the ID tokens will be disabled.

How to use Blazor to send email thru Azure website

If I am creating a Blazor App base on Asp.net Host template and I have a paid subscription for Azure. I would like to know how to send an email when user have entered the required info.
Here the code for Asp.netCore and I am not sure how to use it for my case using Blazor to send thru Azure website. Would appreciate if you can provide some reference to read or a sample code to try out.
Thanks
using System.Net.Mail;
MailMessage mailMessage = new MailMessage();
mailMessage.From = new MailAddress("email1#somewebsite.com");
mailMessage.To.Add(new MailAddress("email2#somewebsite.com"));
mailMessage.Subject = "Your subject";
mailMessage.IsBodyHtml = true;
mailMessage.Body = "Email body";
SmtpClient client = new SmtpClient();
client.Credentials = new System.Net.NetworkCredential("email1#somewebsite.com", "password");
client.Host = "smtpout.asia.secureserver.net";
client.Send(mailMessage);

Use the Outlook/Office365 REST API to send mail from connected email address

I am trying to send an email using the Outlook/Office 365 REST API, and I am trying to send it as an address that I have as a "Connected Account". Attempting to send the message returns a `` error. However, the API will let me create a draft with this address.
Additionally, I can send the API-created draft just fine, and I can also create and send messages as this account from the web interface.
Is there a way to authorize the API to be able to send a message as an address for a connected account?
No, the API doesn't support this today. It has to do with the scope of the permissions that you consent to. "Allow this app to send mail as you" covers sending from your account, but not from another account, even if you have been granted access.
Another thing you can think about is to leverage App-only authentication. You can configure a Azure AD App to have App-only authentication. After that, all the request will behalf of that app id and you should be able to delegate that app id to send email to anyone on behalf of the user you want.
The following is the steps:
Create a Azure AD application.
Configure your Azure AD Application to allow App-only token by
following Build service and daemon apps in Office 365. You also
need a certificate for app-only token request.
Go to your Azure AD Application->Configuration, Click "Add
application" to add "Office 365 Exchange Online". Select "Send email
as any user" under "Application permission" dropdown box. It allows
your Azure AD App to have permission to send email on behalf of
someone.
Once you have Azure AD application configured, you can refer the
following code for sending email on behalf of a specific user.
string tenantId = "yourtenant.onmicrosoft.com";
string clientId = "your client id";
string resourceId = "https://outlook.office.com/";
string resourceUrl = "https://outlook.office.com/api/v2.0/users/service#contoso.com/sendmail"; //this is your on behalf user's UPN
string authority = String.Format("https://login.windows.net/{1}", AUTHORITYURL, tenantId);
string certificatPath = #"c:\test.pfx"; //this is your certficate location.
string certificatePassword = "xxxx"; // this is your certificate password
var itemPayload = new
{
Message = new
{
Subject = "Test email",
Body = new { ContentType = "Text", Content = "this is test email." },
ToRecipients = new[] { new { EmailAddress = new { Address = "test#cotoso.com" } } }
}
};
//if you need to load from certficate store, use different constructors.
X509Certificate2 certificate = new X509Certificate2(certficatePath, certificatePassword, X509KeyStorageFlags.MachineKeySet);
AuthenticationContext authenticationContext = new AuthenticationContext(authority, false);
ClientAssertionCertificate cac = new ClientAssertionCertificate(clientId, certificate);
//get the access token to Outlook using the ClientAssertionCertificate
var authenticationResult = await authenticationContext.AcquireTokenAsync(resourceId, cac);
string token = authenticationResult.AccessToken;
//initialize HttpClient for REST call
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);
client.DefaultRequestHeaders.Add("Accept", "application/json");
//setup the client post
HttpContent content = new StringContent(JsonConvert.SerializeObject(itemPayload));
//Specify the content type.
content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json;odata=verbose");
HttpResponseMessage result = await client.PostAsync(url, content);
if(result.IsSuccessStatusCode)
{
//email send successfully.
}else
{
//email send failed. check the result for detail information from REST api.
}
For a complete explanation, please reference to my blog Send email on behalf of a service account using Office Graph API
I hope it helps and let me know if you have questions.

Sending IM with Skype for Business Online from Console App

I am trying to set up a C# console app that can send notifications/reminders to users via Skype for Business online from a generic AD account. I was excited to see the other day that according to this page, UCWA is now supported in Skype for Business online: https://msdn.microsoft.com/en-us/library/office/mt650889.aspx.
I've been trying to follow this tutorial to get this set up: https://msdn.microsoft.com/en-us/library/office/mt590891(v=office.16).aspx. So far I haven't really had much luck... I have my application set up in Azure AD but I get stuck at the "Requesting an access token using implicit grant flow" step of that article (not 100% certain I'm taking the correct actions before that either)... so far I have this:
string clientId = "xxxxxxxx"
string resourceUri = "https://webdir.online.lync.com";
string authorityUri = "https://login.windows.net/common/oauth2/authorize";
AuthenticationContext authContext = new AuthenticationContext(authorityUri);
UserCredential cred = new UserCredential("username", "password");
string token = authContext.AcquireToken(resourceUri, clientId, cred).AccessToken;
var poolReq = CreateRequest("https://webdir.online.lync.com/autodiscover/autodiscoverservice.svc/root", "GET",token);
var poolResp = GetResponse(poolReq);
dynamic tmp = JsonConvert.DeserializeObject(poolResp);
string resourcePool = tmp._links.user.href;
Console.WriteLine(resourcePool);
var accessTokenReq = CreateRequest("https://login.windows.net/common/oauth2/authorize"
+ "?response_type=id_token"
+ "&client_id=" + clientId
+ "&redirect_uri=https://login.live.com/oauth20_desktop.srf"
+ "&state=" + Guid.NewGuid().ToString()
+ "&resource=" + new Uri(resourcePool).Host.ToString()
, "GET",token);
var accessTokenResp = GetResponse(accessTokenReq);
my GetResponse and CreateRequest methods:
public static string GetResponse(HttpWebRequest request)
{
string response = string.Empty;
using (HttpWebResponse httpResponse = request.GetResponse() as System.Net.HttpWebResponse)
{
//Get StreamReader that holds the response stream
using (StreamReader reader = new System.IO.StreamReader(httpResponse.GetResponseStream()))
{
response = reader.ReadToEnd();
}
}
return response;
}
public static HttpWebRequest CreateRequest(string uri, string method, string accessToken)
{
HttpWebRequest request = System.Net.WebRequest.Create(uri) as System.Net.HttpWebRequest;
request.KeepAlive = true;
request.Method = method;
request.ContentLength = 0;
request.ContentType = "application/json";
request.Headers.Add("Authorization", String.Format("Bearer {0}", accessToken));
return request;
}
accessTokenResp is an office online logon page, not the access token I need to move forward... so I'm stuck. I've tried quite a few variations of the above code.
I've been scouring the net for more examples but can't really find any, especially since UCWA support for Office 365 is so new. Does anyone have an example of how to do what I am trying to do or can point me to one? Everything I've found so far hasn't really even been close to what I'm trying. I can't use the Skype for Business client SDK unfortunately either as it doesn't meet all of my requirements.
I came to a working solution using ADAL (v3), with the help of steps outlined at
Authentication using Azure AD
Here the steps, which involve requesting multiple authentication tokens to AAD using ADAL
Register your application, as Native Application, in Azure AD.
Perform autodiscovery to find user's UCWA root resource URI.
This can be done by performing a GET request on
GET https://webdir.online.lync.com/Autodiscover/AutodiscoverService.svc/root?originalDomain=yourdomain.onmicrosoft.com
Request an access token for the UCWA root resource returned in the autodiscovery response, using ADAL
For instance, your root resource will be at
https://webdir0e.online.lync.com/Autodiscover/AutodiscoverService.svc/root/oauth/user?originalDomain=yourdomain.onmicrosoft.com
you'll have to obtain a token from AAD for resource https://webdir0e.online.lync.com/
Perform a GET on the root resource with the bearer token obtained from ADAL
GET https://webdir0e.online.lync.com/Autodiscover/AutodiscoverService.svc/root/oauth/user?originalDomain=yourdomain.onmicrosoft.com
This will return, within the user resource, the URI for applications resource, where to create your UCWA application. This in my case is:
https://webpoolam30e08.infra.lync.com/ucwa/oauth/v1/applications
Residing then in another domain, thus different audience / resource, not included in the auth token previously obatained
Acquire a new token from AAD for the host resource where the home pool and applications resource are (https://webpoolam30e08.infra.lync.com in my case)
Create a new UCWA application by doing a POST on the applications URI, using the token obtained from ADAL
Voilá, your UCWA application is created. What I notice at the moment, is that just few resources are available, excluding me / presence. So users' presence can be retrieved, but self presence status can't be changed.
I've been able however to retrieve my personal note, and the following resources are available to me:
people
communication
meetings
Show me some code:
Function to perform the flow obtaining and switching auth tokens
public static async Task<UcwaApp> Create365UcwaApp(UcwaAppSettings appSettings, Func<string, Task<OAuthToken>> acquireTokenFunc)
{
var result = new UcwaApp();
result.Settings = appSettings;
var rootResource = await result.Discover365RootResourceAsync(appSettings.DomainName);
var userUri = new Uri(rootResource.Resource.GetLinkUri("user"), UriKind.Absolute);
//Acquire a token for the domain where user resource is
var token = await acquireTokenFunc(userUri.GetComponents(UriComponents.SchemeAndServer, UriFormat.SafeUnescaped));
//Set Authorization Header with new token
result.AuthToken = token;
var usersResult = await result.GetUserResource(userUri.ToString());
//
result.ApplicationsUrl = usersResult.Resource.GetLinkUri("applications");
var appsHostUri = new Uri(result.ApplicationsUrl, UriKind.Absolute).GetComponents(UriComponents.SchemeAndServer, UriFormat.SafeUnescaped);
//Acquire a token for the domain where applications resource is
token = await acquireTokenFunc(appsHostUri);
//Set Authorization Header with new token
result.AuthToken = token;
//
var appResult = await result.CreateApplicationAsync(result.ApplicationsUrl, appSettings.ApplicationId, appSettings.UserAgent, appSettings.Culture);
return result;
}
Usage code ato retrieve OAuth tokens using ADAL
var ucSettings = new UcwaAppSettings
{
UserAgent = "Test Console",
Culture = "en-us",
DomainName = "yourdomain.onmicrosoft.com",
ApplicationId = "your app client id"
};
var acquireTokenFunc = new Func<string, Task<OAuthToken>>(async (resourceUri) =>
{
var authContext = new AuthenticationContext("https://login.windows.net/" + ucSettings.DomainName);
var ar = await authContext.AcquireTokenAsync(resourceUri,
ucSettings.ApplicationId,
new UserCredential("myusername", "mypassword"));
return new OAuthToken(ar.AccessTokenType, ar.AccessToken, ar.ExpiresOn.Ticks);
});
var app = await UcwaApp.Create365UcwaApp(ucSettings, acquireTokenFunc);
It should be of course possible to avoid hard-coding username and password using ADAL, but this was easier for PoC and especially in case of Console Application as you asked
I've just blogged about this using a start-to-finish example, hopefully it will help you. I only go as far as signing in, but you can use it with another post I've done on sending IMs using Skype Web SDK here (see day 13 and 14) and combine the two, it should work fine.
-tom
Similar to Massimo's solution, I've created a Skype for Business Online C# based console app that demonstrates how to sign and use UCWA to create/list/delete meetings and change user presence. I haven't gotten around to extending it to send IM's, but you're certainly welcome to clone my repository and extend it to your needs. Just drop in your Azure AD tenant name and native app ID into the code.
I think they just turned this on today - I was doing something unrelated with the Skype Web SDK samples and had to create a new Azure AD app, and noticed that there are two new preview features for receiving conversation updates and changing user information.
Now everything in the Github samples works for Skype For Business Online.

Identity 2.1 email service

I am developing a MVC 5 internet application, and am wishing to send an email using the SendGrid service when my application is deployed to Azure.
I have found some resource links, yet each different code implementation that I use, sends the email very slowly. I have chosen to use the code from this link: http://www.codeproject.com/Articles/762427/ASP-NET-Identity-Setting-Up-Account-Validation-and
Here is my code:
public class EmailService : IIdentityMessageService
{
public Task SendAsync(IdentityMessage message)
{
// Credentials:
var sendGridUserName = "myusername";
var sentFrom = "test#email.com";
var sendGridPassword = "mypassword";
// Configure the client:
var client =
new System.Net.Mail.SmtpClient("smtp.sendgrid.net", Convert.ToInt32(587));
client.Port = 587;
client.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network;
client.UseDefaultCredentials = false;
// Creatte the credentials:
System.Net.NetworkCredential credentials =
new System.Net.NetworkCredential(sendGridUserName, sendGridPassword);
client.EnableSsl = true;
client.Credentials = credentials;
// Create the message:
var mail =
new System.Net.Mail.MailMessage(sentFrom, message.Destination);
mail.Subject = message.Subject;
mail.Body = message.Body;
// Send:
return client.SendMailAsync(mail);
}
}
The email takes many minutes to send. Why is this? How fast should the email be sent on average, and do I need to optimize my code in any way? Also, rather than using SendGrid, is there a better resource to use that I should use?
Thanks in advance.
Somewhere on Sendgrid documentation (can't find it now unfortunately) I have seen recommendation that if you use their REST API endpoints instead of SMPT, the emails will arrive quicker. And Sendgrid provides C# library to use their API. Give it a go.
It's possible SendGrid is deferring or delaying your sends. Is there any defer or delay activity in your SendGrid dashboard?
You can also connect to the SendGrid Webhook Events to see exactly what's going on with your emails.

Resources