Google Api in C# .net throwing TokenResponseException when I send email - c#

Getting the following error when trying to send from local dev environment for google API. Not sure the right way to attack it. Any advice would be appreciated. Here is the Full Text of the method I am working on.
This is all Google code.
private const string ApplicationName = "<FromGoogle>";
private const string SenderEmailAddress = "<FromGoogle>";
private const string ClientId = "<FromGoogle>";
private const string ClientSecret = "<FromGoogle>";
private static GmailService _service;
private static StringWriter _message;
public static Message SendMail(string subject, string body, params string[] recipients)
{
string[] scopes = { GmailService.Scope.GmailCompose, GmailService.Scope.GmailSend };
ClientSecrets secrets = new ClientSecrets() { ClientId = ClientId, ClientSecret =
ClientSecret };
string folder = HttpContext.Current.Server.MapPath("~/App_Data") + "/gmail-credentials.json";
UserCredential credential = GoogleWebAuthorizationBroker.AuthorizeAsync(secrets,
scopes, "user", CancellationToken.None, new FileDataStore(folder, true)).Result;
_service = new GmailService(new BaseClientService.Initializer() { HttpClientInitializer
= credential, ApplicationName = ApplicationName });
MailMessage msg = new MailMessage
{
Subject = subject,
Body = body,
From = new MailAddress(SenderEmailAddress)
};
foreach (var recipient in recipients) msg.To.Add(new MailAddress(recipient));
msg.ReplyTo.Add(msg.From);
_message = new StringWriter();
msg.Save(_message);
Message result = _service.Users.Messages.Send(new Message { Raw =
Base64UrlEncode(_message.ToString()) }, "me").Execute();
return result;
}
private static string Base64UrlEncode(string input)
{
var inputBytes = Encoding.UTF8.GetBytes(input);
// Special "url-safe" base64 encode.
return Convert.ToBase64String(inputBytes)
.Replace('+', '-')
.Replace('/', '_')
.Replace("=", "");
}
I get the following exception
Exception thrown: 'Google.Apis.Auth.OAuth2.Responses.TokenResponseException'
in Google.Apis.dll
Additional information: Error:"invalid_grant", Description:"", Uri:""

In the end the code was correct. Turns out to be an authorisation issue with Google to which Doctor Jones referred.
After working through the code I changed the ClientId to the Client email. Google specifically did not like that and brought up a web page and told me I was denied.
When I put the code back as it was I ran the test below again and it brought up a google authorisation webpage and after having gone through that the tests were working.
[TestMethod()]
public void SendMailTest()
{
string subject ="subject";
string body = "body";
string recipient = "test#test.com";
Message result = null;
try
{
result = MailTools.SendMail(subject, body, recipient);
}
catch (Exception ex)
{
Assert.Fail(ex.Message);
}
result.ShouldNotBeNull();
}

Related

Sending email with OAUTH2 and smtp.gmail (C#)

I need to send a simple email, but using authentication. Using AppPasswords is not an option.
My difficulty is to retrieve the response after sending the authorization and at what point should I generate the email. I know that to send the email I must use the password and authentication user identity.
Here's what I've done.
Credentials are read from a file
ClientSecrets varClientSecrets = new ClientSecrets();
UserCredential credential;
using (var stream =
new FileStream(pathFile, FileMode.Open, FileAccess.Read,FileShare.Read))
{
varClientSecrets = GoogleClientSecrets.FromStream(stream).Secrets;
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
varClientSecrets,
new[] { "email", "profile", "https://mail.google.com/" },
"use",
CancellationToken.None,
new FileDataStore(credPath, true)
).Result;
strCLIENT_ID = varClientSecrets.ClientId;
strCLIENT_SECRET = varClientSecrets.ClientSecret;
}
// Create Gmail API service.
var service = new GmailService(new BaseClientService.Initializer
{
HttpClientInitializer = credential,
ApplicationName = "XXX"
});
Get credential data
// Define parameters of request.
UsersResource.LabelsResource.ListRequest request = service.Users.Labels.List("me");
ConsultaWeb CW = new ConsultaWeb();
IRestResponse irrRetornoServidor = null;
strSCOPE = credential.Token.Scope;
strREDIRECT_URI = "https://accounts.google.com/o/oauth2/v2/auth";
strTokenURL = "https://www.googleapis.com/oauth2/v4/token";
/// model: {Authorization: token_type base64(userEmail:userPassword)}
strHeader = "Authorization: " + credential.Token.TokenType + " "
+ Base64.EncodeToBase64(userEmail + ":" + userPassword);
strURL = "https://accounts.google.com/o/oauth2/v2/auth"
+ "?scope=" + strSCOPE
+ "&access_type=offline"
+ "&include_granted_scopes=true"
+ "&response_type=code"
+ "&state=state_parameter_passthrough_value"
+ "&redirect_uri=" + strREDIRECT_URI
+ "&client_id=" + strCLIENT_ID;
strServidorRetorno = CW.RequisicaoWebREST(strURL, GET, JSON
, out irrRetornoServidor, "", "", "", "", strHeader);
// Return from OAuth 2.0 server
// OAuth 2.0 server responds to your application's access request
// using the URL specified in the request.
////If the user approves the access request, the response
//will contain an authorization code. If the user does not approve the request,
//the response will contain an error message.
//The authorization code or error message that is returned to the web server
//appears on the query string, as shown below:
strAuthCode = "";
Get response from server
if ((short)irrRetornoServidor.StatusCode == (short)RegrasGlobais.HTTPStatusCode.OK)
{
if (irrRetornoServidor.ResponseUri.AbsolutePath.Contains("error"))
{
// An error response:
// https://oauth2.example.com/auth?error=access_denied
return -1;
}
else if (irrRetornoServidor.ResponseUri.AbsolutePath.Contains("ServiceLogin"))
{
//An authorization code response
// https://oauth2.example.com/auth?code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7
// strAuthCode = "P7q7W91a-oMsCeLvIaQm6bTrgtp7";
// how to get the autorization response, if this open in the browser
strAuthCode = irrRetornoServidor.ResponseUri.Query.ToString();
}
}
else
{
return -1;
}
send the email
// Gmail API server address
//MailMessage msg = new MailMessage();
// build mail
thks
my problem was and how to do the authentication before sending the email. Now I got it. Thanks.
Im a little confused as to what it is you are trying to do. You say you want to send an email using the SMTP server yet you are connecting to the gmail api. Why not just send your emails via the gmail api then?
Assuming you have just gone in the wrong direction. You should know that the SmtpClient can handle the client from the google .Net client library directly. Just let it get its access token when needed.
await client.AuthenticateAsync (oauth2, CancellationToken.None);
If all you want to do is send an email from the smtp server. Try the following sample.
Full sample
using Google.Apis.Auth.OAuth2;
using Google.Apis.Util.Store;
using MailKit.Net.Smtp;
using MailKit.Security;
using MimeKit;
var to = "test#Gmail.com";
var from = "test#gmail.com";
var path = #"C:\YouTube\dev\credentials.json";
var scopes = new[] { "https://mail.google.com/" };
var credential = GoogleWebAuthorizationBroker.AuthorizeAsync(GoogleClientSecrets.FromFile(path).Secrets,
scopes,
"GmalSmtpUser",
CancellationToken.None,
new FileDataStore(Directory.GetCurrentDirectory(), true)).Result;
var message = new EmailMessage()
{
From = from,
To = to,
MessageText = "This is a test message using https://developers.google.com/gmail/imap/xoauth2-protocol",
Subject = "Testing GmailSMTP with XOauth2"
};
try
{
using (var client = new SmtpClient())
{
client.Connect("smtp.gmail.com", 465, true);
var oauth2 = new SaslMechanismOAuth2 (message.From, credential.Token.AccessToken);
await client.AuthenticateAsync (oauth2, CancellationToken.None);
client.Send(message.GetMessage());
client.Disconnect(true);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
public class EmailMessage
{
public string To { get; set; }
public string From { get; set; }
public string Subject { get; set; }
public string MessageText { get; set; }
public MimeMessage GetMessage()
{
var body = MessageText;
var message = new MimeMessage();
message.From.Add(new MailboxAddress("From a user", From));
message.To.Add(new MailboxAddress("To a user", To));
message.Subject = Subject;
message.Body = new TextPart("plain") { Text = body };
return message;
}
}

gmail api Send Mail not working C# Console Application (Insufficient Authentication Scopes)

I am new to google cloud / gmail API. In c# I would like to use their gmail api to:
logon to google cloud - works
read List items - works
send email - does not work
The Api in step 3 Returns Insufficient Request Scopes (403) I feel confident I am logged on to my cloud account: The line of code i suspect most is this:
static string[] Scopes = { GmailService.Scope.GmailAddonsCurrentActionCompose, GmailService.Scope.GmailAddonsCurrentMessageAction };
I am getting this error
Request had insufficient authentication scopes. [403]
Errors [
Message[Insufficient Permission] Location[ - ] Reason[insufficientPermissions] Domain[global]
]
// Code
class Program
{
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/gmail-dotnet-quickstart.json
static string[] Scopes = { GmailService.Scope.GmailAddonsCurrentActionCompose, GmailService.Scope.GmailAddonsCurrentMessageAction };
static string ApplicationName = "Gmail API .NET Quickstart";
static void Main(string[] args)
{
UserCredential credential;
using (var stream =
new FileStream("credentials.json", FileMode.Open, FileAccess.Read))
{
// The file token.json stores the user's access and refresh tokens, and is created
// automatically when the authorization flow completes for the first time.
string credPath = "token.json";
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
"user",
CancellationToken.None,
new FileDataStore(credPath, true)).Result;
Console.WriteLine("Credential file saved to: " + credPath);
}
// Create Gmail API service.
var service = new GmailService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
// Define parameters of request.
UsersResource.LabelsResource.ListRequest request = service.Users.Labels.List("me");
// List labels.
IList<Label> labels = request.Execute().Labels;
Console.WriteLine("Labels:");
if (labels != null && labels.Count > 0)
{
foreach (var labelItem in labels)
{
Console.WriteLine("{0}", labelItem.Name);
}
}
else
{
Console.WriteLine("No labels found.");
}
string plainText = "Body Test";
var newMsg = new Google.Apis.Gmail.v1.Data.Message();
newMsg.Raw = Program.Base64UrlEncode(plainText.ToString());
try
{
service.Users.Messages.Send(newMsg, "me").Execute();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
/*
{"Google.Apis.Requests.RequestError\r\nRequest had insufficient authentication scopes.
[403]\r\nErrors [\r\n\tMessage[Insufficient Permission] Location[ - ] Reason[insufficientPermissions] Domain[global]\r\n]\r\n"} Google.GoogleApiException
*/
Console.Read();
}
public static string Base64UrlEncode(string input)
{
var inputBytes = System.Text.Encoding.UTF8.GetBytes(input);
return Convert.ToBase64String(inputBytes).Replace("+", "-").Replace("/", "_").Replace("=", "");
}
}
//Output from above
Credential file saved to: token.json
Labels:
CHAT
SENT
INBOX
IMPORTANT
TRASH
DRAFT
SPAM
CATEGORY_FORUMS
CATEGORY_UPDATES
CATEGORY_PERSONAL
CATEGORY_PROMOTIONS
CATEGORY_SOCIAL
STARRED
UNREAD
Sent Messages
Pa0
P
Insurance
Junk E-mail
Licenses
Notes
Personal
Receipts
Travel
Work
Tickets
**Google.Apis.Requests.RequestError
Request had insufficient authentication scopes. [403]
Errors [
Message[Insufficient Permission] Location[ - ] Reason[insufficientPermissions] Domain[global]
]**
Okay:
I decided to take the credentials file provided by GMAIL.API and put into a single line Environment Variable and Do a JSON Convert to a GoogleClientSecrets:
private static GoogleClientSecrets GetSecretsFromEnvironment()
{
var environmentConfiguration = new ConfigurationBuilder()
.AddEnvironmentVariables()
.Build();
var secretsEnv = environmentConfiguration["GoogleSecrets"];
var secrets = JsonConvert.DeserializeObject<GoogleClientSecrets>(secretsEnv);
return secrets;
}
the appsettings.json
{
"MailSettings": {
"account": "mark.d.wardell#gmail.com",
"subject": "Please Confirm Account",
"from": "mark.d.wardell#gmail.com",
"HTML": "<b>Hello {0}</b>"
}
}
credentials.json as provided by google cloud console. I made into a single line string and added to EnvironmentVariable
And the calling code:
using Google.Apis.Auth.OAuth2;
using Google.Apis.Gmail.v1;
using Google.Apis.Services;
using Google.Apis.Util.Store;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Mail;
using System.Threading;
using System.Threading.Tasks;
namespace SendMail
{
class Program
{
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/gmail-dotnet-quickstart.json
static string[] Scopes = { GmailService.Scope.GmailAddonsCurrentActionCompose, GmailService.Scope.GmailAddonsCurrentMessageAction, GmailService.Scope.GmailSend };
static string ApplicationName = "Restful Resting Place";
static async Task Main(params string[] args)
{
try
{
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
Dictionary<string, string> MailSettings;
MailSettings = configuration.GetSection("MailSettings").GetChildren().ToDictionary(x => x.Key, x => x.Value);
MailSettings.Add("to", args[0]);
MailSettings.Add("link", args[1]);
GoogleClientSecrets gSecrets = GetSecretsFromEnvironment();
string credPath = "token.json";
UserCredential gcredential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
gSecrets.Secrets,
Scopes,
MailSettings["account"],
CancellationToken.None,
new FileDataStore(credPath, true));
var service = new GmailService(new BaseClientService.Initializer()
{
HttpClientInitializer = gcredential,
ApplicationName = ApplicationName,
});
SendItTwo(service, MailSettings);
Console.WriteLine()
}catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private static GoogleClientSecrets GetSecretsFromEnvironment()
{
var environmentConfiguration = new ConfigurationBuilder()
.AddEnvironmentVariables()
.Build();
var secretsEnv = environmentConfiguration["GoogleSecrets"];
var secrets = JsonConvert.DeserializeObject<GoogleClientSecrets>(secretsEnv);
return secrets;
}
public static void SendItTwo(GmailService gmail, Dictionary<string,string> dict)
{
MailMessage mailmsg = new MailMessage();
{
mailmsg.Subject = dict["subject"];
mailmsg.Body = string.Format(dict["HTML"],dict["link"]);
mailmsg.From = new MailAddress(dict["from"]);
mailmsg.To.Add(new MailAddress(dict["to"]));
mailmsg.IsBodyHtml = true;
}
////add attachment if specified
if (dict.ContainsKey("attachement"))
{
if (File.Exists(dict["attachment"]))
{
Attachment data = new Attachment(dict["attachment"]);
mailmsg.Attachments.Add(data);
}else
{
Console.WriteLine("Error: Invalid Attachemnt");
}
}
//Make mail message a Mime message
MimeKit.MimeMessage mimemessage = MimeKit.MimeMessage.CreateFromMailMessage(mailmsg);
Google.Apis.Gmail.v1.Data.Message finalmessage = new Google.Apis.Gmail.v1.Data.Message();
finalmessage.Raw = Base64UrlEncode(mimemessage.ToString());
var result = gmail.Users.Messages.Send(finalmessage, "me").Execute();
}
public static string Base64UrlEncode(string input)
{
var inputBytes = System.Text.Encoding.UTF8.GetBytes(input);
return Convert.ToBase64String(inputBytes).Replace("+", "-").Replace("/", "_").Replace("=", "");
}
}
}

PlatformNotSupported Exception when calling AddUserAsync .NET Core 2.0

I am trying to write some code that creates a user in Azure AD using the Graph API. I started w/ an example off the net, but right now it fails when adding the user, on the line
await adClient.Users.AddUserAsync(userGraphObj);
In the CreateUser() method below. The error I get is
I am using .NET Core 2.0, debugging on Windows 7. Googling around and I found that they brought serialization back for 2.0, but only for specific types.
I don't really care. How can I add a user to Azure AD in code?
const String appClientID = "2be733f1-88c3-6482-8e2a-5e9631fc3a32";
const String tenant = "espn.onmicrosoft.com";
const String authString = "https://login.microsoftonline.com/" + tenant;
const String authClientSecret = "dDdaVGee315s65ewDSWEwfdw7wq5efDNO5C3cvN4RA";
const String resAzureGraphAPI = "https://graph.windows.net";
const String serviceRootURL = resAzureGraphAPI + appClientID;
private ActiveDirectoryClient GetAADClient()
{
Uri serviceRoot = new Uri(serviceRootURL);
ActiveDirectoryClient adClient = new ActiveDirectoryClient(
serviceRoot, async () => await GetAppTokenAsync());
return adClient;
}
private static async Task<String> GetAppTokenAsync()
{
AuthenticationContext authenticationContext = new AuthenticationContext(authString, false);
ClientCredential clientCred = new ClientCredential(appClientID, authClientSecret);
AuthenticationResult authResult = await authenticationContext.AcquireTokenAsync(resAzureGraphAPI, clientCred);
return authResult.AccessToken;
}
public async Task<IActionResult> CreateUser()
{
var adClient = GetAADClient();
//Construct The User
String userEmail = "TestUser#example.com";
String mailNickname = userEmail.Split(new char[] { '#' }).FirstOrDefault();
var userGraphObj = new Microsoft.Azure.ActiveDirectory.GraphClient.User()
{
GivenName = "Test",
Surname = "User",
Mobile = "13133124044",
MailNickname = mailNickname,
DisplayName = "Test User",
AccountEnabled = true
};
await adClient.Users.AddUserAsync(userGraphObj);
return Ok(tempPassword);
}
Microsoft itself recommends not to use the Azure AD Graph API anymore, in favor of the Microsoft Graph API (cf blog post).
If you don't have a strong requirement to use the Azure AD API, here are the steps to create a user via the latest API.
Disclaimer :
I never managed to successfully acquire a token from a desktop application
I haven't really understood how the permissions scopes are supposed to be used (here it seems to want a URL, but in the examples it's usually a list of strings, such as User.ReadWrite.All or Directory.ReadWrite.All)
Code to acquire a token:
const String appClientID = "2be733f1-88c3-6482-8e2a-5e9631fc3a32";
const String tenant = "brazzers.onmicrosoft.com";
const String authString = "https://login.microsoftonline.com/" + tenant;
const String authClientSecret = "dDdaVGee315s65ewDSWEwfdw7wq5efDNO5C3cvN4RA";
public static GraphServiceClient GetAuthenticatedClient()
{
var delegateAuthenticationProvider = new DelegateAuthenticationProvider(
async (requestMessage) =>
{
var accessToken = await GetAppTokenAsync();
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", accessToken);
}
);
return new GraphServiceClient(delegateAuthenticationProvider);
}
private static async Task<String> GetAppTokenAsync()
{
// this doesn't work for desktop apps,
// and PublicClientApplication throws a NotImplementedException
var cca = new ConfidentialClientApplication(
appClientID,
authString,
"http://www.example.com/", // no redirect
new ClientCredential(authClientSecret),
new TokenCache(),
new TokenCache());
var authResult = await cca.AcquireTokenForClientAsync(new[] { $"https://graph.microsoft.com/.default" });
return authResult.AccessToken;
}
Code to create a user (courtesy of the samples):
public async Task<User> CreateUser(GraphServiceClient graphClient)
{
// This snippet gets the tenant domain from the Organization object to construct the user's email address.
var organization = await graphClient.Organization.Request().GetAsync();
var domain = organization.CurrentPage[0].VerifiedDomains.ElementAt(0).Name;
// Add the user.
var userEmail = "TestUser#" + domain;
var mailNickname = userEmail.Split(new char[] { '#' }).FirstOrDefault();
return await graphClient.Users.Request().AddAsync(new User
{
AccountEnabled = true,
DisplayName = "Test User",
MailNickname = mailNickname,
PasswordProfile = new PasswordProfile
{
Password = "super_strong_password"
},
UserPrincipalName = userEmail
});
}

Gmail API read message

I'm trying to read an email using gmail api. But the format of the body message is unreadable.
static void Main(string[] args)
{
UserCredential credential;
using (var stream =
new FileStream("client_secret.json", FileMode.Open, FileAccess.Read))
{
string credPath = System.Environment.GetFolderPath(
System.Environment.SpecialFolder.Personal);
credPath = Path.Combine(credPath, ".credentials/gmail-dotnet-quickstart.json");
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
"user",
CancellationToken.None,
new FileDataStore(credPath, true)).Result;
Console.WriteLine("Credential file saved to: " + credPath);
}
// Create Gmail API service.
var service = new GmailService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
UsersResource.MessagesResource.ListRequest request = service.Users.Messages.List("me");
IList<Message> messages = request.Execute().Messages;
if (messages != null && messages.Count > 0)
{
foreach (var messageItem in messages)
{
var readMessage = service.Users.Messages.Get("me", messageItem.Id).Execute();
var body = readMessage.Payload.Parts[0].Body.Data;
}
} }
When I debug my test application, the body variable gets the value:
body "DQpLaW5kIFJlZ2FyZHMsDQoNCldpbGwNCg0KV2lsbCBLZWx0eQ0KMzIzLjI1Mi44Njk5DQp3a2VsdHlAZ21haWwuY29tIDxtYWlsdG86d2tlbHR5QGdtYWlsLmNvbT4NCmh0dHBzOi8vd3d3LmZhY2Vib29rLmNvbS9iaWdibHVlZG93bnRvd24gPGh0dHBzOi8vd3d3LmZhY2Vib29rLmNvbS9iaWdibHVlZG93bnRvd24-DQp3d3cubWV0cm9saWZlcHJvcGVydGllcy5jb20gPGh0dHA6Ly93d3cubWV0cm9saWZlcHJvcGVydGllcy5jb20vPg0KDQpCZWdpbiBmb3J3YXJkZWQgbWVzc2FnZToNCg0KRnJvbTogIkNSRVhpIiA8bm90aWZpY2F0aW9uc0BjcmV4aS5jb20-DQpTdWJqZWN0OiBJbmR1c3RyaWFsIENSRSBBc3NldHMgRm9yIFNhbGUgfCBHcmVhdCBPaGlvIExvY2F0aW9ucyB8IEVhc3kgQWNjZXNzIHwgTkFJIFNwcmluZw0KRGF0ZTogSnVseSAxNCwgMjAxNyBhdCA5OjAxOjQwIEFNIFBEVA0KVG86IHdrZWx0eUBnbWFpbC5jb20NClJlcGx5LVRvOiBpbmZvQGNyZXhpLmNvbQ0KDQogPGh0dHA6Ly9lbWFpbC1saW5rcy5jcmV4aS5jb20vd2YvY2xpY2s_dXBuPWpvS3FmZnZFU3Y1RDU2eXI3cmpPd2lBREcwN3p4ek1EdnI0ZnNsdEY5QWJIT1Z1V2JrU0ZhWXN4aTNXY2hucE11SmhUTUlDZjQ3WVo5bDBoY0RtSGZ2NFl0VXJoN1g2TDh2ZzdMQnlkZi0yQmZzOFZSYVk5UGJyYzg4YjdsT1NRUDZfMGxhbklERktDMWU0bHUtMkZZZjdLNjA1d2ZJOWZHdXp2amlNdjYwUERQNFVCTzd5cjRBTHVjTW8tMkZpRDFadXFSTUV5Z2RISVBhRGU3M2FGeGhLS1hBaS0yRlo5UlVzVFhzampqVS0yRndZN1lIa045M1BQRnlaNEQ1QTBQRHlzSElxMWdIYlQtMkJJRWYtMkZRMDBUQU8yV0lMNC0yQlFVU2hueDlhVnhWSXc5NjRFYmNta0FVVDB5SWhqTXl5Mm9na29FWTR5QWZ1czhUQWVJZDBsU0RXMVBMQi0yQmctMkYxMUJRY3gzYWRoYmJxcG1Ma2FGdTdXU3U1STFkQmJjaXN5bW5tcHIyWXVpdTNOdHdiOFpsTm5jLTJGSDdrdThYU3FxTVdIOHhsWFA2Ykp0VTdVYVN4M2IxcVBITlNDblNDYWRhSkEyeEw0MVlGMjFlTm8wcEZXWTVVQk9LengzYkctMkI4V0g2QXpNR1FkNDJhZS0yRkFMN3c1VkxrSlZ1LTJGdTFlR0lNYjBkV3VmdnZkemlXVjgtMkZHcy0yQks1a3BYUi0yQmJhTUwzUE5NTFhpMWRHUjhEWEZndzh1WGZMSFdNUmc0R2Y2MWMwb2JNUEQtMkI4c1QtMkJ1NTFtRj4JDQogDQogPGh0dHA6Ly9lbWFpbC1saW5rcy5jcmV4aS5jb20vd2YvY2xpY2s_dXBuPVVnWW9yUXo0" string
Does anyone know why?
Thanks
Change this line
var body = readMessage.Payload.Parts[0].Body.Data;
to
var body = Base64UrlDecode(readMessage.Payload.Parts[0].Body.Data);
And add this method in your code:
public static string Base64UrlDecode(string input)
{
if (string.IsNullOrWhiteSpace(input))
return "<strong>Message body was not returned from Google</strong>";
string InputStr = input.Replace("-", "+").Replace("_", "/");
return System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(InputStr));
}
Also, to handle multiparts and no multiparts returns, you may use this code:
if (ml.Payload.Parts != null) {
foreach (void bParts_loopVariable in ml.Payload.Parts) {
bParts = bParts_loopVariable;
if (bParts.MimeType == "text/html") {
if (bParts.Body != null) {
dynamic mp = bParts.Body;
if (mp != null) {
return Base64UrlDecode(mp.Data);
}
}
}
}
} else {
return Base64UrlDecode(ml.Payload.Body.Data);
}
The body is Base64 encoded.
You need to call Convert.FromBase64String(string) to get the plain text.
You should use readMessage.GetRaw() method. See below how to decode the base64 string:
byte[] data = Convert.FromBase64String(readMessage.GetRaw());
string messageString = Encoding.UTF8.GetString(data);
see ref https://developers.google.com/gmail/api/v1/reference/users/messages/get

Using Youtube ApiV3 locally as well as on server

I am a beginner in C# so it will be helpful if you explain the issue in simple words. I have issue regarding uploading a video on my YouTube channel through server using YouTube API v3 but when I run my code locally I have no issues uploading a video.But hosting on IIS/Server gives object reference error.
Below is the code I am trying to execute for video uploading which is written on upload button.
protected async void btnUpload_Click(object sender, EventArgs e)
{
if (txtVideoTitle.Text != "" && txtFileUpload.HasFile)
{
date = DateTime.Now;
string CLIENT_ID = ConfigurationManager.AppSettings["ClientId"];
string CLIENT_SECRET = ConfigurationManager.AppSettings["ClientSecret"];
var youtubeService = AuthenticateOauth(CLIENT_ID, CLIENT_SECRET,"singleuser");
if (youtubeService == null) throw new ArgumentNullException("youtubeService");
var video = new Video();
video.Snippet = new VideoSnippet();
video.Snippet.Title = txtVideoTitle.Text;
video.Snippet.Description = txtVideoDescription.Text;
video.Snippet.Tags = new string[] { "tag1", "tag2" };
video.Status = new VideoStatus();
video.Status.PrivacyStatus = "unlisted";
if (video == null) throw new ArgumentNullException("video");
var filename = txtFileUpload.FileName;
Stream filepath = txtFileUpload.PostedFile.InputStream;
var videosInsertRequest = youtubeService.Videos.Insert(video,"snippet,status", filepath, "video/*");
videosInsertRequest.ResponseReceived += videosInsertRequest_ResponseReceived;
await videosInsertRequest.UploadAsync();
message.Text = "Video Uploaded Successfully!!!";
}
else
{
message.Text = "Please enter required details...";
}
}
public static YouTubeService AuthenticateOauth(string cLIENT_ID, string cLIENT_SECRET, string v)
{
string[] scopes = new string[] { YouTubeService.Scope.Youtube,
YouTubeService.Scope.YoutubeForceSsl,
YouTubeService.Scope.Youtubepartner,
YouTubeService.Scope.YoutubepartnerChannelAudit,
YouTubeService.Scope.YoutubeReadonly,
YouTubeService.Scope.YoutubeUpload};
try
{
// here is where we Request the user to give us access, or use the Refresh Token that was previously stored in %AppData%
UserCredential credential = GoogleWebAuthorizationBroker.AuthorizeAsync(new ClientSecrets { ClientId = cLIENT_ID, ClientSecret = cLIENT_SECRET }
, scopes
, v
, CancellationToken.None
, new FileDataStore("Drive.Auth.Store")).Result;
YouTubeService service = new YouTubeService(new YouTubeService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Web"
});
if (service == null) throw new ArgumentNullException("service");
return service;
}
catch (Exception ex)
{
Console.WriteLine(ex.InnerException);
return null;
}
}
As you can see in the above code I have handled youtube service where it throws exception because it receives null value when I host it on server or IIS on company network.But when I run my code locally(development machine) It doesn't throw any exception.
I have spent days solving the issue but to no avail.Any help will be appreciated.
The exception message is
Server Error in '/' Application.
Value cannot be null.
Parameter name: youtubeService
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.ArgumentNullException: Value cannot be null.
Parameter name: youtubeService

Categories

Resources