I tried read my emails content. I need the complete text email. I read a lot of Stack Overflow questions but no working. My message.Payload.Body.Data is a lot of times null. I need a think like message.Snippet but with the complete message.
My code is :
//Login
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,
"admin",
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");
var inboxlistRequest = service.Users.Messages.List("me");
inboxlistRequest.LabelIds = "INBOX";
inboxlistRequest.IncludeSpamTrash = false;
var emailListResponse = inboxlistRequest.Execute();
foreach (var mail in emailListResponse.Messages)
{
var mailId = mail.Id;
var threadId = mail.ThreadId;
Message message = service.Users.Messages.Get("me", mailId).Execute();
Console.WriteLine(message.Payload.Body.Data);
}
I try too thinks like :
foreach (var part in message.Payload.Parts)
{
byte[] data = Convert.FromBase64String(part.Body.Data);
string decodedString = Encoding.UTF8.GetString(data);
Console.WriteLine(decodedString);
}
But no work because i don't find content in Payload.
Related
I need to read the gmail inbox feed using Oauth2.0. Simulating in the postman,
Auth URL : https://accounts.google.com/o/oauth2/auth
Access Token URL : https://accounts.google.com/o/oauth2/token
Client ID : XXXXX.apps.googleusercontent.com
Client Secret : XXXXX
Scope : https://mail.google.com/mail/feed/atom
GrantType: Authorization Code
I requested the token and used it on the header
Authorization - Bearer XXXXXXXXXX.
And I made the request via GET right in my scope and got my email feeds. Works!!!
The postman generates a code in C #, but the token expires.
var client = new RestClient("https://mail.google.com/mail/feed/atom/");
var request = new RestRequest(Method.GET);
request.AddHeader("postman-token", "d48cac24-bd3e-07b5-c616-XXXXXXXX");
request.AddHeader("cache-control", "no-cache");
request.AddHeader("authorization", "Bearer ya29.a0AfH6SMDZlUmw0xLHAoYIJuIfTkXXXXXXXXQSPP17GmXT26fJEfWB9w8UiwQ2YF32-nOp6zY9H_lwJEEXXXXXXXXXXXYK4e0tcZkieGbBl5Eow2M-7Gxp20kfDtXXXXXVjiXymLXyMkYEI");
IRestResponse response = client.Execute(request);
I'm trying to do it via Google.Api, using GoogleAuthorizationCodeFlow and already using token refresh.
With the code below, I got authorization from the application, but I can't read the xml atom feed
GoogleAuthorizationCodeFlow flow;
var assembly = Assembly.GetExecutingAssembly();
var clientfile = #"client_secrets.json";
using (var stream = new FileStream(clientfile, FileMode.Open, FileAccess.Read))
{
flow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
DataStore = new FileDataStore("StoreTest"),
ClientSecretsStream = stream,
Scopes = new[] { "https://mail.google.com/mail/feed/atom/" }
});
}
var uri = Request.Url.ToString();
var code = Request["code"];
if (code != null)
{
var token = flow.ExchangeCodeForTokenAsync(UserId, code,
uri.Substring(0, uri.IndexOf("?")), CancellationToken.None).Result;
// Extract the right state.
var oauthState = AuthWebUtility.ExtracRedirectFromState(
flow.DataStore, UserId, Request["state"]).Result;
Response.Redirect(oauthState);
}
else
{
var result = new AuthorizationCodeWebApp(flow, uri, uri).AuthorizeAsync(UserId,
CancellationToken.None).Result;
if (result.RedirectUri != null)
{
// Redirect the user to the authorization server.
Response.Redirect(result.RedirectUri);
}
else
{
// The data store contains the user credential, so the user has been already authenticated.
var gmailfeed = new GmailService(new BaseClientService.Initializer
{
HttpClientInitializer = result.Credential,
ApplicationName = "GetFeed",
});
var inboxlistRequest = gmailfeed.Users.Messages.List("me");
inboxlistRequest.LabelIds = "Label_19780355190759038";
inboxlistRequest.IncludeSpamTrash = false;
var emailListResponse = inboxlistRequest.Execute();
foreach (var mail in emailListResponse.Messages)
{
var mailId = mail.Id;
var threadId = mail.ThreadId;
Message message = gmailfeed.Users.Messages.Get("me", mailId).Execute();
Console.WriteLine((message.Snippet));
}
}
}
I got to read the email, but I need the xml atom feed.
Could someone help me how I make this call to get the atom feed, using the granted token. If there is an easier way to do it too, it would be cool to share.
Thank you
Resolved using respsharp, restclient!!
tks
My goal is to retrieve all emails that exist under one label within my gmail account and forward those emails to another email address. Here's what i have so far:
string[] Scopes = { GmailService.Scope.GmailReadonly, GmailService.Scope.GmailSend, };
string ApplicationName = "APP NAME";
UserCredential credential;
using (var stream = new FileStream("credentials.json", FileMode.Open, FileAccess.Read))
{
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);
}
var service = new GmailService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
var labelList = service.Users.Messages.List("me#gmail.com");
labelList.LabelIds = "LABEL_NAME";
var emailListResponse = labelList.Execute();
if (emailListResponse != null && emailListResponse.Messages != null)
{
foreach (var email in emailListResponse.Messages)
{
//THIS IS WHERE I WOULD LIKE TO FORWARD this email TO ANOTHER EMAIL ADDRESS?
//How to set TO?
//service.Users.Messages.Send(email, "me#gmail.com").Execute();
}
}
I am able to retrieve the emails but i'm not sure how to forward. Thank you for your help
To forward a message you have to get it and add the recipient's email to the "To:" field.
Alternatively, you could set up a filter to forward all emails with the Label you have to another address.
I created a console application which sends an email to an address, it shows like:
private static string[] Scopes = { GmailService.Scope.GmailCompose, GmailService.Scope.GmailSend };
private static string ApplicationName = "Gmail API Quickstart";
private const string SUBJECT = "Some simple subject";
private static string[] emails = new string[] { "teodorescumihail2008#live.com" };
static void Main(string[] args)
{
UserCredential credential;
using (var stream =
new FileStream("client_secret.json", FileMode.Open, FileAccess.Read))
{
string credPath = Environment.GetFolderPath(
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,
});
var msg = new AE.Net.Mail.MailMessage
{
Subject = SUBJECT,
Body = "Test body",
From = new MailAddress("teodorescumihail2008#gmail.com")
};
msg.To.Add(new MailAddress("teodorescumihail2008#live.com"));
StringWriter sw = new StringWriter();
msg.Save(sw);
var result = service.Users.Messages.Send(new Message
{
Raw = Base64UrlEncode(sw.ToString())
}, "me").Execute();
Console.Read();
}
private static string Base64UrlEncode(string input)
{
var inputBytes = System.Text.Encoding.UTF8.GetBytes(input);
// Special "url-safe" base64 encode.
return Convert.ToBase64String(inputBytes)
.Replace('+', '-')
.Replace('/', '_')
.Replace("=", "");
}
When execute sending email, I received:
Where is my mistake ?
I assumed you changed your scope in the code without reauthorize/getting a new credential file from Gmail. The problem is GmailAPI does not know that your scope is updated. You have to reauthorize your app in GmailAPI by deleting your app permission and regenerate your credentials.json so that your scope is updated on GmailAPI.
To delete your app permission: click here
I am using the following code to get authoriziation and upload to YouTube:
I have requested my token from google and the user has logged in and I have got my authorization token back.
I have exchanged this for a refresh and access token using the following:
using (WebClient client = new WebClient())
{
byte[] response =
client.UploadValues("https://accounts.google.com/o/oauth2/token", new NameValueCollection()
{
{"code", Session["authCode"].ToString()},
{"redirect_uri", "http://YouTubeTest.org/testpage.aspx"},
{
"client_id", clientID
},
{"client_secret", secret},
{"grant_type", "authorization_code"}
});
string result =Encoding.UTF8.GetString(response);
XElement node = XElement.Parse(JsonConvert.DeserializeXNode(result, "Root").ToString());
Session["refreshtoken"] = node.Element("refresh_token").Value;
}
These details are then stored.
When a user clicks to upload a video I initialise the youtube service as follows:
ClientSecrets secrets = new ClientSecrets()
{
ClientId = CLIENT_ID,
ClientSecret = CLIENT_SECRET
};
var token = new TokenResponse { RefreshToken = REFRESH_TOKEN };
var credentials = new UserCredential(new GoogleAuthorizationCodeFlow(
new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = secrets
}),
"user",
token);
var service = new YouTubeService(new BaseClientService.Initializer()
{
HttpClientInitializer = credentials,
ApplicationName = "TestProject"
});
At this point I would like to know if the refresh token I have sent over is valid, but there doesn't seem to be any way of telling.
The only way I seem to know is when I actually try and upload a video by doing the following:
public String UploadVideo(Stream stream, String title, String desc, String[] tags, String categoryId, Boolean isPublic)
{
var video = new Video();
video.Snippet = new VideoSnippet();
video.Snippet.Title = title;
video.Snippet.Description = desc;
video.Snippet.Tags = tags;
video.Snippet.CategoryId = categoryId; // See https://developers.google.com/youtube/v3/docs/videoCategories/list
video.Status = new VideoStatus();
video.Status.PrivacyStatus = isPublic ? "public" : "private";
var videosInsertRequest = youtube.Videos.Insert(video, "snippet,status", stream, "video/*");
videosInsertRequest.ProgressChanged += insertRequest_ProgressChanged;
videosInsertRequest.ResponseReceived += insertRequest_ResponseReceived;
videosInsertRequest.Upload();
return UploadedVideoId;
}
void insertRequest_ResponseReceived(Video video)
{
UploadedVideoId = video.Id;
}
void insertRequest_ProgressChanged(Google.Apis.Upload.IUploadProgress progress)
{
// You can handle several status messages here.
switch (progress.Status)
{
case UploadStatus.Failed:
UploadedVideoId = "FAILED";
^^ If the token is invalid at this point the progress has an exception with "Invalid_grant"
break;
case UploadStatus.Completed:
break;
default:
break;
}
}
How do I find out before I try an upload if the refresh token I have is valid?
It's difficult to recover nicely from it at this point, so ideally I'd like to be able to check it when or after I initialize the youtube service.
Validating a token is part of the Google Identity documentation. It suggests that you can validate a token by requesting in a web service endpoint.
You can call https://www.googleapis.com/oauth2/v3/tokeninfo along with your access_token as a parameter
https://www.googleapis.com/oauth2/v3/tokeninfo?access_token=1/fFBGRNJru1FQd44AzqT3Zg
The response will have a JSON object that describes the token or an error. More details about this can be found on the referenced page in the documentation above.
I'm trying to create a worksheet in a spreadsheet which is a copy of the existing one. Via Google Docs user interface it is done by 'Duplicate' function of the context menu of a worksheet. Is it possible to copy the whole sheet at once and insert it to the other one?
This code:
public void CopyLastTab(SpreadsheetEntry spreadsheet, string newTabName)
{
WorksheetEntry tabToCopy = GetLastTab(spreadsheet);
tabToCopy.Title.Text = newTabName;
newTab = service.Insert(GetAllWorksheets(spreadsheet), tabToCopy);
}
adds only a new empty worksheet.
Copying cell by cell is too long and the matter is I need conditional formatting used on the previous sheet too. Please help.
Old question but just spent several hours trying to find an answer. The following works for C# .net 6:
Note this assumes you have an instance of Google SheetsService
(Google.APIs.Sheets.v4) that has already been authenticated. I'll post some authentication code below.
public void Duplicate(int SourceSheetId, string NewSheetName) {
var batch = new BatchUpdateSpreadsheetRequest();
batch.Requests = new List<Request>();
batch.Requests.Add(new Request() {
DuplicateSheet = new DuplicateSheetRequest() {
NewSheetName = NewSheetName,
SourceSheetId = SourceSheetId
},
});
var req = Service.Spreadsheets.BatchUpdate(batch, SheetID); //public SheetsService Service; property of parent class
var response = req.Execute();
}
private void _authenticate()
{
UserCredential credential;
using (var stream = new FileStream("credentials.json", FileMode.Open, FileAccess.ReadWrite))
{
string credPath = "token.json";
var cancelToken = new CancellationToken();
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
_scopes,
YOUR-EMAIL-HERE,
cancelToken,
new FileDataStore(credPath, true)).Result;
//credential.RevokeTokenAsync(cancelToken); //UNCOMMENT TO LOG OUT
}
Service = new SheetsService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "",
});
}