Can I read messages from gmail using gmail api and c#? - c#

I want read all messages in my gmail account using c# and gmail api.
Can I do this?
I read a lot of articles in Gmail API, but i couldn't read messages.
Also I want to read a body of messages or header.
I will be very glad if someone can help me :)
I use this code snippet:
public static List<Message> ListMessages(GmailService service, String userId)
{
List<Message> result = new List<Message>();
UsersResource.MessagesResource.ListRequest request = service.Users.Messages.List(userId);
do
{
try
{
ListMessagesResponse response = request.Execute();
result.AddRange(response.Messages);
request.PageToken = response.NextPageToken;
}
catch (Exception e)
{
Console.WriteLine("An error occurred: " + e.Message);
}
} while (!String.IsNullOrEmpty(request.PageToken));
return result;
}
And this:
foreach (var item in ListMessages(service,"me"))
MessageBox.Show(item.Snippet);
But in a result I have empty message box.

It works for me
var inboxlistRequest = service.Users.Messages.List("your-email-address");
inboxlistRequest.LabelIds = "INBOX";
inboxlistRequest.IncludeSpamTrash = false;
//get our emails
var emailListResponse = inboxlistRequest.Execute();
foreach (var mail in emailListResponse.Messages)
{
var mailId = mail.Id;
var threadId = mail.ThreadId;
Message message = service.Users.Messages.Get("your-email-address", mailId).Execute();
Console.WriteLine(message.Snippet);
}

Yes you should have no issue doing what you say. I would suggest reading the documentation a bit more.
First you have to authenticate - the following shows how to do this with a service account (more details here https://developers.google.com/gmail/api/auth/web-server)
serviceAccountEmail = primaryLink.serviceEmailAddress;
certificate = new X509Certificate2(AppDomain.CurrentDomain.BaseDirectory + "certs//" + primaryLink.certificate, primaryLink.certificatePassword, X509KeyStorageFlags.Exportable);
try
{
credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
User = z.us.emailAccount,
Scopes = new[] { "https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/userinfo.profile", "https://mail.google.com/" }
}.FromCertificate(certificate));
if (credential.RequestAccessTokenAsync(CancellationToken.None).Result)
{
gs = new GmailService(
new Google.Apis.Services.BaseClientService.Initializer()
{
ApplicationName = "Example",
HttpClientInitializer = credential
});
}
else
{
throw new Exception("gmail authentication Error.");
}
}
catch (Exception ex)
{
throw ex;
}
ListMessagesResponse respM = reqM.Execute();
if (respM.Messages != null)
{
foreach (Message m in respM.Messages)
{}
}
Once you have the message List you can iterate through the messages and either use a MIME parser or traverse the message structure to get the header, body etc.
There are lots of posts in this forum which go through how to do that.

I searched for a full example, without luck, but this is my working example. Based on https://developers.google.com/gmail/api/guides
Authenticate : https://developers.google.com/gmail/api/auth/web-server
get ALL emails
loop through all emails by Id, and request message etc.
here is the code snippet to get the first email's atachments, but you can simply loop over all foundIds to get all emails, and use message.snippet to get body :
List<string> foundIds = new List<string>();
string outputDir = "/EXAMPLE/EXAMPLE/"; // your preferred Dir to save attachments to
List<Google.Apis.Gmail.v1.Data.Thread> resultThread = new List<Google.Apis.Gmail.v1.Data.Thread>();
UsersResource.ThreadsResource.ListRequest requestThread = service.Users.Threads.List("me");
do
{
try
{
ListThreadsResponse responseThread = requestThread.Execute();
resultThread.AddRange(responseThread.Threads);
foreach (var item in responseThread.Threads )
{
foundIds.Add(item.Id);
}
requestThread.PageToken = responseThread.NextPageToken;
}
catch (Exception e)
{
Console.WriteLine("An error occurred: " + e.Message);
}
} while (!String.IsNullOrEmpty(requestThread.PageToken));
try
{
Message message = service.Users.Messages.Get("me", foundIds[0]).Execute();
IList<MessagePart> parts = message.Payload.Parts;
foreach (MessagePart part in parts)
{
if (!String.IsNullOrEmpty(part.Filename))
{
String attId = part.Body.AttachmentId;
MessagePartBody attachPart = service.Users.Messages.Attachments.Get("me", foundIds[0], attId).Execute();
// Converting from RFC 4648 base64 to base64url encoding
// see http://en.wikipedia.org/wiki/Base64#Implementations_and_history
String attachData = attachPart.Data.Replace('-', '+');
attachData = attachData.Replace('_', '/');
byte[] data = Convert.FromBase64String(attachData);
File.WriteAllBytes(Path.Combine(outputDir, part.Filename), data);
}
}
}
catch (Exception e)
{
Console.WriteLine("An error occurred: " + e.Message);
}

I would suggest taking a look at this article on how to handle the actual response structure. It can be somewhat complex with the way the Gmail API gives the results back to you.
https://sigparser.com/developers/email-parsing/gmail-api/

#BlackCat, Your ListMessages looks good. Now, to get the message body, you have to decode MimeType "text/plain" or "text/html". For eg:
public static void GetBody(GmailService service, String userId, String messageId, String outputDir)
{
try
{
Message message = service.Users.Messages.Get(userId, messageId).Execute();
Console.WriteLine(message.InternalDate);
if (message.Payload.MimeType == "text/plain")
{
byte[] data = FromBase64ForUrlString(message.Payload.Body.Data);
string decodedString = Encoding.UTF8.GetString(data);
Console.WriteLine(decodedString);
}
else
{
IList<MessagePart> parts = message.Payload.Parts;
if (parts != null && parts.Count > 0)
{
foreach (MessagePart part in parts)
{
if (part.MimeType == "text/html")
{
byte[] data = FromBase64ForUrlString(part.Body.Data);
string decodedString = Encoding.UTF8.GetString(data);
Console.WriteLine(decodedString);
}
}
}
}
Console.WriteLine("----");
}
catch (Exception e)
{
Console.WriteLine("An error occurred: " + e.Message);
}
}

Related

How to attach file (pdf) to SOAP response?

My code (testing):
[WebMethod]
public string SoapWithAttachment(string suggestionId, int agentId)
{
byte[] bytes = null;
elemPoliciesWS.suggestionPaymentResult returnPolicyFile = new elemPoliciesWS.suggestionPaymentResult();
elemPoliciesWS.suggestion sug = new elemPoliciesWS.suggestion();
if (elem.State.ToString().ToLower() == "faulted")
{
elem = new elemPoliciesWS.IelemPoliciesWSClient();
}
sug = elem.GetSuggestionDetailsBySuggestionId(suggestionId);
if (sug != null)
{
sug.EncodedSuggestionIdStr = EncodeSuggestionId(suggestionId.ToLower());
if (sug.AgentId == agentId)
{
try
{
returnPolicyFile = elem.getPolicyMekif(sug);
bytes = Convert.FromBase64String(returnPolicyFile.Suggestion.PolicySpecificationBase64StringPDF);
File.WriteAllBytes(#"C:\Logs\file.pdf", bytes);
}
catch (Exception ex)
{
LogWriter.WriteToLog("SoapWithAttachment", " Exeception StackTrace: ", ex.StackTrace);
}
}
}
return returnPolicyFile.Suggestion.PolicySpecificationBase64StringPDF; }
Currently in SOAP response I have string in base64 format:
<SoapWithAttachmentResponse xmlns="http://ayl-vdev/webservices/">
<SoapWithAttachmentResult>JVBERi0xLjYNJeLjz9MNCjY1IDAgb2JqDTw8L0.....</SoapWithAttachmentResult>
</SoapWithAttachmentResponse>
As result I have on local machine a correct pdf file.
How can I attach this file to SOAP response that it will be downloadable to clients PC?

How to retrieve custome error message in Web Client request?

Server side code to return file
[HttpGet]
public HttpResponseMessage GetVersionList(string Credentials, string VersionNumber)
{
try
{
string UserLoginStatus = objUtility.LoginUser(objUtility.GetUserName(Credentials), objUtility.GetPassWord(Credentials));
if (UserLoginStatus == "OK")
{
var path = objUtility.GetFileName(VersionNumber);
if (path != null)
{
return FileAsAttachment(path, VersionNumber + ".exe");
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.OK, "File Not Found.");
}
}
else
{
// Return reason why it failed.
// It could be not authorized user, Not Active user, UID/Password wrong etc.
// Store into UserLoginStatus variable and pass show to client
return Request.CreateResponse<string>(HttpStatusCode.OK, UserLoginStatus);
}
}
catch (System.Exception ex)
{
return Request.CreateResponse<string>(HttpStatusCode.OK, ex.Message);
}
}
// Win app code to download file
using (WebClient webClient = new WebClient())
{
try
{
webClient.DownloadFile(serverUrl, (txtPath.Text + "\\" + txtVersion.Text + ".exe"));
}
catch (WebException wex)
{
// Show error message here
}
}
}
catch (Exception ex)
{
lblStatus.Text = ex.InnerException + " <br> " + ex.Message;
}
}
This is how I did it recently for a rest service I wrote for a POS. (myErrorType is just a dummy for whatever class you are actually using...)
using (var response = request.GetResponse())
{
using (var reader = new StreamReader(response.GetResponseStream()))
{
var reply = reader.ReadToEnd();
myErrorType result = Newtonsoft.Json.JsonConvert.DeserializeObject<myErrorType>(reply);
return result.Status;
// do something with the results
}
}
To Throw a custom error :
myErrorType errresponse = new myErrorType();//dummy class, create your own...
throw new WebFaultException<myErrorType>(errresponse, HttpStatusCode.BadRequest);

Error accessing wcf service asynchronously in c# .net: unauthorised

I am building a standard odata client using: Microsoft.Data.Services.Client.Portable Windows 8 VS2013
I have added a service reference to the project (TMALiveData) with authorisation. Now I want to retrieve data but when I do I get the following error: DataServiceQueryException.InvalidOperationException
I looked at the DataServiceQueryResult object the status code is: System.Net.HttpStatusCode.Unauthorized
When I added the reference it asked me for my credentials, so I assumed this would be sent with each query, but it clearly isn't. How do I add the credentials (password and username) in the DataServiceQuery object? Below is my current code:
public class testLSCon
{
static string mResult;
public static string result { get { return mResult; } }
public static void testREADLiveConnection()
{
Uri tmaLiveDataRoot = new Uri("https://xxx.azurewebsites.net/xxx.svc/");
TMLiveData.TMALiveData mLiveData = new TMLiveData.TMALiveData(tmaLiveDataRoot);
mResult = null;
DataServiceQuery<TMLiveData.JobType> query = (DataServiceQuery<TMLiveData.JobType>)mLiveData.JobTypes.Where(c => c.IsActive == true);
mResult = "Trying to READ the data";
try
{
query.BeginExecute(OnQueryComplete, query);
}
catch (Exception ex)
{
mResult = "Error on beginExecute: " + ex.Message;
}
}
private static void OnQueryComplete(IAsyncResult result)
{
DataServiceQuery<TMLiveData.JobType> query = (DataServiceQuery<TMLiveData.JobType>) result.AsyncState;
mResult = "Done!";
try
{
foreach (TMLiveData.JobType jobType in query.EndExecute(result))
{
mResult += jobType.JobType1 + ",";
}
}
catch (DataServiceClientException ex)
{
mResult = "Error looping for items: (DataServiceClientException)" + ex.Message;
}
catch (DataServiceQueryException ex2)
{
mResult = "Error looping for items: (DataServiceQueryException)" ;
}
catch (Exception ex3)
{
mResult = "Error looping for items: (general exception)" + ex3.Message;
}
}
}
You can either set it to the credentials of the current user (so the credentials of the user the client is running as)
mLiveData.Credentials = CredentialCache.DefaultCredentials;
or if you need to impersonate another user you can use this (obviously swap the strings for the details you need - maybe passed in from config.
mLiveData.Credentials = new System.Net.NetworkCredential("UserName", "Password", "Domain");

get gmail contacts images

I am trying to get google contact image from gmail, using google api 3.
I have used the code below to read the stream to get the photo:
public static void DownloadPhoto(ContactsRequest cr, Contact entry)
{
string filename = "c:\\gcontacts\\" + entry.GetHashCode() + ".jpg";
Stream photoStream = cr.GetPhoto(entry);
FileStream outStream = File.OpenWrite(filename);
try
{
byte[] buffer = new byte[photoStream.Length];
photoStream.Read(buffer, 0, (int)photoStream.Length);
outStream.Write(buffer, 0, (int)photoStream.Length);
photoStream.Close();
outStream.Close();
}
catch (Exception ex)
{
}
}
I am getting the below error:
Content not modified.
https://www.google.com/m8/feeds/photos/media/myemail/610f985888b0911.
I use this function to call the service
public static void PrintAllContacts(ContactsRequest cr)
{
Feed<Contact> f = cr.GetContacts();
foreach (Contact entry in f.Entries)
{
if (entry.Name.FullName != null)
{
Console.WriteLine(entry.Name.FullName);
Console.WriteLine(entry.PhotoUri.AbsoluteUri);
DownloadPhoto(cr, entry);
}
}
}
and this is the request
RequestSettings rsLoginInfo = new RequestSettings("appname", "#gmail.com", "pass");
rsLoginInfo.AutoPaging = true;
ContactsRequest cRequest = new ContactsRequest(rsLoginInfo);
instead of
cr.GetPhoto(entry)
use
cr.Service.Query(entry.PhotoUri);
It says there is a problem in the request. You should check where you make the request and share it with us, you didn't post that part in your question.
You can find the documentation here: https://developers.google.com/google-apps/contacts/v3/#retrieving_a_contacts_photo

You don't have permission to post in a group

I've finished a program in C# which integrates with Facebook and posts to more than one group in a click
but I am facing a problem right now when there is a group that you don't have a permission to post to I can't complete posting to the rest
here's the post function
I put it in other Class
public static bool PostImage(Frm form,string AccessToken, string Status, string ImagePath)
{
try
{
if (form.listBox2 .SelectedItems .Count > 0)
{
string item;
foreach (int i in form. listBox2.SelectedIndices)
{
item = form.listBox2.Items[i].ToString();
groupid = item;
FacebookClient fbpost = new FacebookClient(AccessToken);
var imgstream = File.OpenRead(ImagePath);
dynamic res = fbpost.Post("/" + groupid + "/photos", new
{
message = Status,
File = new FacebookMediaStream
{
ContentType = "image/jpg",
FileName = Path.GetFileName(ImagePath)
}.SetValue(imgstream)
});
result = true;
}
}
return result;
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
return false;
}
}
You need to put a try catch block inside the loop. Then, in the catch block you log the error (or do whatever you want with it) then continue the loop:
foreach (int i in form. listBox2.SelectedIndices)
{
try
{
item = form.listBox2.Items[i].ToString();
groupid = item;
FacebookClient fbpost = new FacebookClient(AccessToken);
var imgstream = File.OpenRead(ImagePath);
dynamic res = fbpost.Post("/" + groupid + "/photos", new
{
message = Status,
File = new FacebookMediaStream
{
ContentType = "image/jpg",
FileName = Path.GetFileName(ImagePath)
}.SetValue(imgstream)
});
result = true;
}
catch(exception excp)
{
//Do something with the exception
}
}
Now I don't know exactly how your code works, but this should give you a rough idea.

Categories