1: using global::Google.Apis.Auth.OAuth2;
2: using global::Google.Apis.Gmail.v1;
3: using global::Google.Apis.Gmail.v1.Data;
4: using global::Google.Apis.Services;
5: using global::Google.Apis.Util.Store;
6: using System;
7: using System.Collections.Generic;
8: using System.IO;
9: using System.Text;
10: using System.Threading;
11:
12: namespace Ia.Cl.Model
13: {
14: ////////////////////////////////////////////////////////////////////////////
15:
16: /// <summary publish="true">
17: /// Gmail API support class
18: /// </summary>
19: ///
20: /// <remarks>
21: /// Copyright © 2017-2018 Jasem Y. Al-Shamlan (info@ia.com.kw), Integrated Applications - Kuwait. All Rights Reserved.
22: ///
23: /// This library is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by
24: /// the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
25: ///
26: /// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
27: /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
28: ///
29: /// You should have received a copy of the GNU General Public License along with this library. If not, see http://www.gnu.org/licenses.
30: ///
31: /// Copyright notice: This notice may not be removed or altered from any source distribution.
32: /// </remarks>
33: public class Gmail
34: {
35: //private string serverUser, defaultMailbox;
36:
37: // If modifying these scopes, delete your previously saved credentials at ~/.credentials/gmail-dotnet-quickstart.json
38: private static string[] scopeList;
39: private static string applicationName;
40: private GmailService service;
41: private UsersResource.LabelsResource.ListRequest request;
42: private UsersResource.MessagesResource.SendRequest sendRequest;
43:
44: ////////////////////////////////////////////////////////////////////////////
45:
46: /// <summary>
47: ///
48: /// </summary>
49: public enum MailType
50: {
51: ////////////////////////////////////////////////////////////////////////////
52:
53: /// <summary>
54: ///
55: /// </summary>
56: Plain,
57:
58: ////////////////////////////////////////////////////////////////////////////
59:
60: /// <summary>
61: ///
62: /// </summary>
63: Html
64:
65: ////////////////////////////////////////////////////////////////////////////
66: ////////////////////////////////////////////////////////////////////////////
67: };
68:
69: ////////////////////////////////////////////////////////////////////////////
70:
71: /// <summary>
72: ///
73: /// </summary>
74: public Gmail()
75: {
76: /*
77: * app.config
78: * <add key="imapServerUser" value="*" />
79: */
80:
81: // serverUser = ConfigurationManager.AppSettings["imapServerUser"].ToString();
82:
83: UserCredential credential;
84:
85: //defaultMailbox = "Inbox";
86:
87: scopeList = new string[] { GmailService.Scope.GmailReadonly, GmailService.Scope.GmailSend };
88:
89: applicationName = "Gmail API .NET Quickstart";
90:
91: using (var stream = new FileStream("client_secret.json", FileMode.Open, FileAccess.Read))
92: {
93: string credPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
94:
95: credPath = Path.Combine(credPath, ".credentials/gmail-dotnet-quickstart.json");
96:
97: credential = GoogleWebAuthorizationBroker.AuthorizeAsync(GoogleClientSecrets.Load(stream).Secrets, scopeList, "ofn.gov.kw@gmail.com", CancellationToken.None, new FileDataStore(credPath, true)).Result;
98:
99: Console.WriteLine("Credential file saved to: " + credPath);
100: }
101:
102: // Create Gmail API service.
103: service = new GmailService(new BaseClientService.Initializer() { HttpClientInitializer = credential, ApplicationName = applicationName });
104:
105: // Define parameters of request.
106: request = service.Users.Labels.List("me");
107: }
108:
109: ////////////////////////////////////////////////////////////////////////////
110:
111: /// <summary>
112: ///
113: /// </summary>
114: public void SendEmail(string name, string email, string subject, string content)
115: {
116: global::Google.Apis.Gmail.v1.Data.Message mailMessage = new global::Google.Apis.Gmail.v1.Data.Message();
117:
118: mailMessage.Payload = new MessagePart();
119: mailMessage.Payload.Headers = new List<MessagePartHeader>();
120:
121: mailMessage.Payload.Headers.Add(new MessagePartHeader() { Name = "From", Value = "ofn.gov.kw@gmail.com" });
122: mailMessage.Payload.Headers.Add(new MessagePartHeader() { Name = "Date", Value = DateTime.UtcNow.AddHours(3).ToString() });
123: mailMessage.Payload.Headers.Add(new MessagePartHeader() { Name = "Subject", Value = "Testing..." });
124: mailMessage.Payload.Headers.Add(new MessagePartHeader() { Name = "To", Value = email });
125:
126: mailMessage.Payload.Body = new MessagePartBody();
127: mailMessage.Payload.Body.Data = content;
128: //mailMessage.Payload.Body.Data...IsBodyHtml = (mailType == MailType.Html);
129:
130: /*
131: foreach (System.Net.Mail.Attachment attachment in email.Attachments)
132: {
133: mailMessage.Attachments.Add(attachment);
134: }
135: */
136:
137: //var mimeMessage = global::Google.Apis.Gmail.v1.Data.MimeMessage.CreateFromMailMessage(mailMessage);
138:
139: /*
140: var gmailMessage = new global::Google.Apis.Gmail.v1.Data.Message
141: {
142: Raw = Encode(mimeMessage.ToString())
143: };
144: */
145:
146: sendRequest = service.Users.Messages.Send(mailMessage, "ofn.gov.kw@gmail.com");
147:
148: sendRequest.Execute();
149: }
150:
151: ////////////////////////////////////////////////////////////////////////////
152:
153: /// <summary>
154: ///
155: /// </summary>
156: public static string Encode(string text)
157: {
158: byte[] bytes = System.Text.Encoding.UTF8.GetBytes(text);
159:
160: return System.Convert.ToBase64String(bytes)
161: .Replace('+', '-')
162: .Replace('/', '_')
163: .Replace("=", "");
164: }
165:
166: ////////////////////////////////////////////////////////////////////////////
167:
168: /// <summary>
169: ///
170: /// </summary>
171: public List<string> LabelList
172: {
173: get
174: {
175: // case sensitive
176:
177: List<string> labelList;
178: IList<Label> labelIList;
179:
180: labelList = new List<string>();
181: labelIList = request.Execute().Labels;
182:
183: Console.WriteLine("Labels:");
184:
185: if (labelIList != null && labelIList.Count > 0)
186: {
187: foreach (var labelItem in labelIList)
188: {
189: labelList.Add(labelItem.Name);
190: Console.WriteLine("{0}", labelItem.Name);
191: }
192: }
193: else
194: {
195: Console.WriteLine("No labels found.");
196: }
197:
198: return labelList;
199: }
200: }
201:
202: ////////////////////////////////////////////////////////////////////////////
203:
204: /// <summary>
205: ///
206: /// </summary>
207: public void Test()
208: {
209: string body, from, date, subject;
210: UsersResource.MessagesResource.ListRequest listRequest;
211: ListMessagesResponse listMessagesResponse;
212:
213: from = date = string.Empty;
214:
215: listRequest = service.Users.Messages.List("ofn.gov.kw@gmail.com");
216: listRequest.LabelIds = "SENT"; // case sensitive
217: listRequest.IncludeSpamTrash = false;
218:
219: listMessagesResponse = listRequest.Execute();
220:
221: if (listMessagesResponse != null && listMessagesResponse.Messages != null)
222: {
223: //loop through each email and get what fields you want...
224: foreach (var email in listMessagesResponse.Messages)
225: {
226: var emailInfoRequest = service.Users.Messages.Get("ofn.gov.kw@gmail.com", email.Id);
227: var emailInfoResponse = emailInfoRequest.Execute();
228:
229: if (emailInfoResponse != null)
230: {
231: //loop through the headers to get from, date, subject, body
232:
233: foreach (var messagePartHeader in emailInfoResponse.Payload.Headers)
234: {
235: if (messagePartHeader.Name == "Date") date = messagePartHeader.Value;
236: else if (messagePartHeader.Name == "From") from = messagePartHeader.Value;
237: else if (messagePartHeader.Name == "Subject") subject = messagePartHeader.Value;
238:
239: if (date != "" && from != "")
240: {
241: if (emailInfoResponse.Payload.MimeType == "text/html")
242: {
243: if (emailInfoResponse.Payload.Parts == null && emailInfoResponse.Payload.Body != null)
244: {
245: body = emailInfoResponse.Payload.Body.Data;
246: }
247: else
248: {
249: body = GetNestedParts(emailInfoResponse.Payload.Parts, "");
250: }
251:
252: byte[] data = FromBase64ForUrlString(body);
253: string decodedString = Encoding.UTF8.GetString(data);
254: }
255: }
256: else
257: {
258:
259: }
260: }
261: }
262: }
263: }
264: }
265:
266: ////////////////////////////////////////////////////////////////////////////
267:
268: /// <summary>
269: ///
270: /// </summary>
271: private static String GetNestedParts(IList<MessagePart> part, string curr)
272: {
273: string s;
274:
275: s = curr;
276:
277: if (part == null)
278: {
279: return s;
280: }
281: else
282: {
283: foreach (var partList in part)
284: {
285: if (partList.Parts == null)
286: {
287: if (partList.Body != null && partList.Body.Data != null)
288: {
289: s += partList.Body.Data;
290: }
291: }
292: else
293: {
294: return GetNestedParts(partList.Parts, s);
295: }
296: }
297:
298: return s;
299: }
300: }
301:
302: ////////////////////////////////////////////////////////////////////////////
303:
304: /// <summary>
305: ///
306: /// </summary>
307: public List<string> MailboxList
308: {
309: get
310: {
311: List<string> mailboxList;
312:
313: mailboxList = new List<string>();
314:
315: //foreach (Mailbox mailbox in imap.Mailboxes) mailboxList.Add(mailbox.Name);
316:
317: return mailboxList;
318: }
319: }
320:
321: /*
322: ////////////////////////////////////////////////////////////////////////////
323:
324: /// <summary>
325: ///
326: /// </summary>
327: public void CreateMailbox(string mailboxName)
328: {
329: imap.CreateMailbox(mailboxName);
330: }
331:
332: ////////////////////////////////////////////////////////////////////////////
333:
334: /// <summary>
335: ///
336: /// </summary>
337: public string DeleteMailbox(string mailboxName)
338: {
339: return imap.DeleteMailbox(mailboxName);
340: }
341:
342: ////////////////////////////////////////////////////////////////////////////
343:
344: /// <summary>
345: ///
346: /// </summary>
347: public Header ReadHeader(Mailbox mailbox, int i)
348: {
349: Header header;
350: ActiveUp.Net.Mail.Header aHeader;
351:
352: header = new Header();
353:
354: try
355: {
356: aHeader = mailbox.Fetch.HeaderObject(i);
357:
358: header.MessageId = aHeader.MessageId;
359: header.From = aHeader.From.Email;
360: header.Subject = aHeader.Subject;
361: }
362: catch (Imap4Exception iex)
363: {
364: }
365: catch (Exception ex)
366: {
367: }
368: finally
369: {
370: }
371:
372: return header;
373: }
374:
375: ////////////////////////////////////////////////////////////////////////////
376:
377: /// <summary>
378: ///
379: /// </summary>
380: public int MoveMessagesFromEmailToMailbox(string email, string destinationMailboxName)
381: {
382: int numberOfMessagesMoved;
383: int[] messageOrdinalList;
384: string searchPhrase;
385: Mailbox mailbox;
386:
387: numberOfMessagesMoved = 0;
388:
389: mailbox = imap.SelectMailbox(defaultMailbox);
390:
391: searchPhrase = @"FROM """ + email + @"""";
392:
393: messageOrdinalList = mailbox.Search(searchPhrase);
394:
395: if (messageOrdinalList != null && messageOrdinalList.Length > 0)
396: {
397: // read message and check that from-email value before moving
398: for (int i = messageOrdinalList.Length - 1; i >= 0; i--)
399: {
400: MoveMessage(mailbox, messageOrdinalList[i], destinationMailboxName);
401: numberOfMessagesMoved++;
402: }
403: }
404:
405: return numberOfMessagesMoved;
406: }
407:
408: ////////////////////////////////////////////////////////////////////////////
409:
410: /// <summary>
411: ///
412: /// </summary>
413: public void MoveMessage(string messageId, string destinationMailboxName)
414: {
415: int[] messageOrdinalList;
416: string searchPhrase;
417: Mailbox mailbox;
418: ActiveUp.Net.Mail.Header header;
419:
420: mailbox = imap.SelectMailbox(defaultMailbox);
421:
422: searchPhrase = @"ALL";
423:
424: messageOrdinalList = mailbox.Search(searchPhrase);
425:
426: if (messageOrdinalList != null && messageOrdinalList.Length > 0)
427: {
428: for (int i = messageOrdinalList.Length - 1; i >= 0; i--)
429: {
430: header = mailbox.Fetch.HeaderObject(messageOrdinalList[i]);
431:
432: if (header.MessageId == messageId)
433: {
434: MoveMessage(mailbox, messageOrdinalList[i], destinationMailboxName);
435:
436: break;
437: }
438: }
439: }
440: }
441:
442: ////////////////////////////////////////////////////////////////////////////
443:
444: /// <summary>
445: ///
446: /// </summary>
447: public void MoveMessage(Mailbox mailbox, int messageOrdinal, string destinationMailboxName)
448: {
449: mailbox.MoveMessage(messageOrdinal, destinationMailboxName);
450: }
451:
452: ////////////////////////////////////////////////////////////////////////////
453:
454: /// <summary>
455: /// Message list from Inbox
456: /// </summary>
457: public void MessageList(out List<Message> messageList)
458: {
459: string searchPhrase;
460:
461: searchPhrase = "ALL";
462:
463: SearchPhraseMessageList(searchPhrase, out messageList);
464: }
465:
466: ////////////////////////////////////////////////////////////////////////////
467:
468: /// <summary>
469: /// List of messages from Inbox that were sent from email
470: /// </summary>
471: public void MessageList(string email, out List<Message> messageList)
472: {
473: string searchPhrase;
474:
475: searchPhrase = @"FROM """ + email + @"""";
476:
477: SearchPhraseMessageList(searchPhrase, out messageList);
478: }
479:
480: ////////////////////////////////////////////////////////////////////////////
481:
482: /// <summary>
483: ///
484: /// </summary>
485: private void SearchPhraseMessageList(string searchPhrase, out List<Message> messageList)
486: {
487: Message message;
488: Mailbox mailbox;
489: MessageCollection messageCollection;
490:
491: messageList = new List<Message>();
492:
493: mailbox = imap.SelectMailbox(defaultMailbox);
494:
495: try
496: {
497: messageCollection = mailbox.SearchParse(searchPhrase);
498:
499: foreach (ActiveUp.Net.Mail.Message m in messageCollection)
500: {
501: message = new Message();
502:
503: message.MessageId = m.MessageId;
504: message.From = m.From.Email;
505: message.Subject = m.Subject;
506: message.BodyText = m.BodyText.TextStripped;
507: message.Date = m.Date;
508: message.ReceivedDate = m.ReceivedDate;
509:
510: foreach (ActiveUp.Net.Mail.MimePart mp in m.Attachments)
511: {
512: //if (mp.IsText)
513: //{
514: message.Attachments.Add(new Attachment
515: {
516: FileName = mp.Filename,
517: ContentType = mp.ContentType.MimeType,
518: Content = mp.TextContent
519: });
520: //}
521: }
522:
523: messageList.Add(message);
524:
525: this.Log(string.Format("Success: Message read: {0},{1},{2}", m.MessageId, m.From, m.Subject));
526: }
527: }
528: catch (Imap4Exception iex)
529: {
530: this.Log(string.Format("Imap4 Error: {0}", iex.Message));
531: }
532: catch (Exception ex)
533: {
534: this.Log(string.Format("Failed: {0}", ex.Message));
535: }
536: finally
537: {
538: }
539: }
540:
541: ////////////////////////////////////////////////////////////////////////////
542:
543: /// <summary>
544: ///
545: /// </summary>
546: public List<Header> HeaderList(Mailbox mailbox)
547: {
548: Header header;
549: List<Header> headerList;
550: ActiveUp.Net.Mail.Header aHeader;
551:
552: headerList = new List<Header>(mailbox.MessageCount);
553:
554: try
555: {
556: for (int i = 1; i <= mailbox.MessageCount; i++)
557: {
558: header = new Header();
559:
560: aHeader = mailbox.Fetch.MessageObject(i);
561:
562: header.MessageId = aHeader.MessageId;
563: header.From = aHeader.From.Email;
564: header.Subject = aHeader.Subject;
565:
566: this.Log(string.Format("Success: Header read: {0},{1},{2}", header.MessageId, header.From, header.Subject));
567: }
568: }
569: catch (Imap4Exception iex)
570: {
571: }
572: catch (Exception ex)
573: {
574: }
575: finally
576: {
577: }
578:
579: return headerList;
580: }
581:
582: ////////////////////////////////////////////////////////////////////////////
583:
584: /// <summary>
585: ///
586: /// </summary>
587: public void DeleteMessage(string messageId)
588: {
589: int[] messageOrdinalList;
590: string searchPhrase;
591: Mailbox mailbox;
592: ActiveUp.Net.Mail.Header header;
593:
594: mailbox = imap.SelectMailbox(defaultMailbox);
595:
596: searchPhrase = @"ALL";
597:
598: messageOrdinalList = mailbox.Search(searchPhrase);
599:
600: if (messageOrdinalList != null && messageOrdinalList.Length > 0)
601: {
602: for (int i = messageOrdinalList.Length - 1; i >= 0; i--)
603: {
604: header = mailbox.Fetch.HeaderObject(messageOrdinalList[i]);
605:
606: if (header.MessageId == messageId)
607: {
608: DeleteMessage(mailbox, messageOrdinalList[i]);
609: }
610: }
611: }
612: }
613:
614: ////////////////////////////////////////////////////////////////////////////
615:
616: /// <summary>
617: ///
618: /// </summary>
619: private void DeleteMessage(Mailbox mailbox, int messageOrdinal)
620: {
621: mailbox.DeleteMessage(messageOrdinal, true);
622: }
623: */
624:
625: ////////////////////////////////////////////////////////////////////////////
626:
627: /// <summary>
628: ///
629: /// </summary>
630: public static byte[] FromBase64ForUrlString(string base64ForUrlInput)
631: {
632: int padChars = (base64ForUrlInput.Length % 4) == 0 ? 0 : (4 - (base64ForUrlInput.Length % 4));
633: StringBuilder result = new StringBuilder(base64ForUrlInput, base64ForUrlInput.Length + padChars);
634:
635: result.Append(String.Empty.PadRight(padChars, '='));
636: result.Replace('-', '+');
637: result.Replace('_', '/');
638:
639: return Convert.FromBase64String(result.ToString());
640: }
641:
642: ////////////////////////////////////////////////////////////////////////////
643: ////////////////////////////////////////////////////////////////////////////
644: }
645: }