Below is my working code snippet that retrieves unread emails from custom folder names under Inbox.
foreach (Microsoft.Exchange.WebServices.Data.Folder folder in findFolderResults.Folders)
{
LogFile.AppendLog(folder.DisplayName + " folder found in Inbox.");
if (folder.DisplayName == folderName)
{
LogFile.AppendLog(folder.DisplayName + " matches " + folderName);
ItemView view = new ItemView(emailBatch);
do
{
LogFile.AppendLog("Checking for unread emails in folder " + folder.DisplayName);
emailItemList = service.FindItems(folder.Id, sf, view);
foreach (var emailItem in emailItemList.Items)
{
LogFile.AppendLog("Getting unread emails in folder " + folder.DisplayName);
EmailMessage email = EmailMessage.Bind(service, emailItem.Id);
retrievedEmailList.Add((EmailMessage)email);
}
if (!emailItemList.NextPageOffset.HasValue)
break;
}
while (emailItemList.MoreAvailable);
}
}
There is a variable emailBatch that is currently being configured as 10.
I do understand that this means that it will only check and retrieve 10 unread email at one go.
However, once the 10 email has been added to the list, will it continue to check for unread email?
I would need to add all unread emails to retrievedEmailList, instead of just 10 emails, if it happens.
Thank you.
You need to implement paged searching. You seem to have partially tried this but your code is missing some stuff. I have updated your code and put comments in explaining the new code I've added.
// Set the offset for the paged search.
int offset = 0;
// Set the flag that indicates whether to continue iterating through additional pages.
bool MoreItems = true;
LogFile.AppendLog(folder.DisplayName + " folder found in Inbox.");
if (folder.DisplayName == folderName)
{
// Continue paging while there are more items to page.
while (MoreItems)
{
LogFile.AppendLog(folder.DisplayName + " matches " + folderName);
// Set the ItemView with the page size and offset.
ItemView view = new ItemView(emailBatch, offset, OffsetBasePoint.Beginning);
LogFile.AppendLog("Checking for unread emails in folder " + folder.DisplayName);
emailItemList = service.FindItems(folder.Id, sf, view);
foreach (var emailItem in emailItemList.Items)
{
LogFile.AppendLog("Getting unread emails in folder " + folder.DisplayName);
EmailMessage email = EmailMessage.Bind(service, emailItem.Id);
retrievedEmailList.Add((EmailMessage)email);
}
// Set the flag to discontinue paging.
if (!emailItemList.MoreAvailable)
MoreItems = false;
// Update the offset if there are more items to page.
if (MoreItems)
offset += pageSize;
}
}
Related
I am trying to save last send mail from Outlook to my desktop as .msg format.
But i am getting error with my code in last line of my code as follow:
((Microsoft.Office.Interop.Outlook.MailItem)mail).SaveAs(mydesktop+ "\\Myapplication\\" + subject.Replace(":", "").Replace("/", "").Replace("|", "") + ".msg", Microsoft.Office.Interop.Outlook.OlSaveAsType.olMSG);
Error:System.Runtime.InteropServices.COMException: 'The item has been moved or deleted.'
string mailto = labelControl53.Text + ";" + labelControl56.Text ;
string cc = "myaccount#mymail.com";
string subject= labelControl7.Text + "-" + comboBoxEdit1.Text + "-" + textEdit6.Text + " Yüklemesi hk.";
string mydesktop= Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
Microsoft.Office.Interop.Outlook.Application mailat = new Microsoft.Office.Interop.Outlook.Application();
Microsoft.Office.Interop.Outlook.MailItem mail = (Microsoft.Office.Interop.Outlook.MailItem)mailat.CreateItem(Microsoft.Office.Interop.Outlook.OlItemType.olMailItem);
mail.To = mailto;
mail.CC = cc;
mail.Subject = subject;
mail.Importance = Microsoft.Office.Interop.Outlook.OlImportance.olImportanceHigh;
mail.BodyFormat = Microsoft.Office.Interop.Outlook.OlBodyFormat.olFormatHTML;
mail.HTMLBody = getHTMLupload();
((Microsoft.Office.Interop.Outlook.MailItem)mail).Send();
((Microsoft.Office.Interop.Outlook.MailItem)mail).SaveAs(mydesktop+ "\\Myapplication\\" + subject.Replace(":", "").Replace("/", "").Replace("|", "") + ".msg", Microsoft.Office.Interop.Outlook.OlSaveAsType.olMSG);
System.Runtime.InteropServices.COMException: 'The item has been moved or deleted.'
This mail object is released after send so you don't have access to it.
You probably have to add an event handler. Something like this might work.
((Outlook.ItemEvents_10_Event)mail).Send += new Microsoft.Office.Interop.Outlook.ItemEvents_10_SendEventHandler(SaveSentMail);
static void SaveSentMail(ref bool Cancel)
{
mail.SaveAs(mydesktop+ ....);
}
If you want to save the last sent item in Outlook you need to handle the ItemAdd event of the Items class which comes from the Sent Items folder. Typically mail items are placed into the Sent Items folder as soon as they are sent. However, users or other add-ins may set the DeleteAfterSubmit property which sets a Boolean value that is True if a copy of the mail message is not saved upon being sent, and False if a copy is saved in Sent Items folder.
Or just call the SaveAs before submitting items in Outlook (before the Send method).
I am trying to move all the emails in another folder in outlook which has the subject:
"Message Delivery Failure"
Every time the foreach loop runs the last email is always left in the inbox and the loop breaks.
OutLook.MAPIFolder inBox = mOulook.Application.ActiveExplorer().Session.GetDefaultFolder(OutLook.OlDefaultFolders.olFolderInbox);
OutLook.Items inBoxItems = inBox.Items;
OutLook.MailItem newEmail = null;
//Creating destination folder where emails are going to be moved
Microsoft.Office.Interop.Outlook.MAPIFolder destFolder = null;
if (destFolder == null)
{
destFolder = inBox.Folders["Test"];
}
//moving each email from source to destination
foreach (object eMail in inBoxItems)
{
try
{
newEmail = eMail as Microsoft.Office.Interop.Outlook.MailItem;
if (newEmail != null)
{
string titleSubject = (string)newEmail.Subject;
if (titleSubject == "Message Delivery Failure")
{
newEmail.Move(destFolder);
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
That's probably due to the condition in place if (titleSubject == "Message Delivery Failure"). You can consider to loop through only those needed like
foreach (OutLook.MailItem eMail in ((Microsoft.Office.Interop.Outlook.MailItem)inBoxItems).Select(em => em.Subject == "Message Delivery Failure").ToList())
{
You are changing the collection (by calling Move) while you are iterating over its items.
Use a down "for" loop instead (from Items.Count to 1).
Its dynamic COM_object.
Try to manage in loop.
Problem is when it unread email it also reduce the .Count() in loop.
Try to track all your Mailitems and find it by ConversationID/MessageId and add all Mailitems in List:
List MailItems = new List();
MailItem Email = MailItems.Where(z => z.ConversationID.Equals("ConversationID")).First();
Email.Move(FolderToMove);
hope this question makes sense: Is there a way I can download files from a drive without reiterating the service account every time? So for example, I have a program that allows me to backup my Gapps organization drives. The program currently works like this:
Logs in to each account with the service I created in the Google developer console
Checks the token as a source for changed files from the last time the backup ran to the current execution
IF the token is different, executes a file list request and records the fileId and actual fileName for the files changed, then puts both values into a temporary text document as 2 columns ("fileId,fileName"). Here is what I'm using for the file resource list
Console.WriteLine("Changes detected. Making notes while we go through these.");
if (File.Exists(savelocation + ".deltalog.tok"))
File.Delete(savelocation + ".deltalog.tok");
using (StreamWriter deltalog = new StreamWriter(savelocation + ".deltalog.tok", true))
{
while (pageToken != null)
{
counter1++;
var request = CreateService.BuildService(user).Changes.List(pageToken);
//StreamWriter deltalog = new StreamWriter(savelocation + ".deltalog.tok", true);
request.Fields = "*";
request.Spaces = "drive";
var changes = request.Execute();
foreach (var change in changes.Changes)
{
try
{
string updatedfile = change.File.Name;
//string updatedfile = CreateService.BuildService(user).Files.Get(change.FileId).Execute().Name;
// Record the changed file
Console.WriteLine(user + ": New or changed file found: " + updatedfile + "\n");
logFile.WriteLine(user + ": New or changed file found: " + change.FileId + " --- " + updatedfile);
deltalog.Write(change.FileId + "," + updatedfile+"\n");
deltalog.Flush();
}
Start exporting the files out as documents to my server for backup. To do this, I log into the Gapps domain with my service account 3 different times for one file for each user. Right now, I'm reading the file created from step 3 and splitting the values so that I have the fileId and Filename on hand. The code looks like this:
FilesResource.ListRequest listRequest = CreateService.BuildService(user).Files.List();
listRequest.PageSize = 1000;
listRequest.Fields = "nextPageToken, files(id, name)";
string[] deltafiles = File.ReadAllLines(savelocation + ".deltalog.tok");
IList<Google.Apis.Drive.v3.Data.File> files = listRequest.Execute()
.Files;
Console.WriteLine("\nFiles to backup:\n");
if (deltafiles == null)
{
return;
}
else
{
foreach (var file in deltafiles)
{
try
{
// Our file is a CSV. Column 1 = file ID, Column 2 = File name
var values = file.Split(',');
string fileId = values[0];
string fileName = values[1];
fileName = fileName.Replace('\\', '_').Replace('/', '_').Replace(':', '_').Replace('!', '_').Replace('\'', '_').Replace('*', '_');
Console.WriteLine("Filename: " + values[1]);
logFile.WriteLine("ID: " + values[0] + " - Filename: " + values[1]);
var requestfileid = CreateService.BuildService(user).Files.Get(fileId);
var getfile = CreateService.BuildService(user).Files.Get(fileId).Execute();
var request = CreateService.BuildService(user).Files.Export(fileId, getfile.MimeType);
and so forth.
If I try to change the requestfileid to values[0] (which would be the fileId for that file in the loop), then the MediaDownloader doesn't work because it's no longer part of the Files.Get constructor.
Is there anything I can do, or overlooking, so that the service account only has to log in once to do everything it needs per account?
Hope that gibberish makes sense.
I've been using https://developers.google.com/drive/v3/web/quickstart/dotnet and the API documentation as my source for information, and I got everything working the way I want it to, Except for having to log in as the service multiple times for One file. Any help or point in the right direction would sure be appreciated. Thank you!
So I'm working on an app that will be able to read the outlook calendars for a set of individuals and build an itinerary for them. I've got it pretty much working except that when I scrape a user's calendar, I'm not getting any information on the events they have marked as private.
Let me make it clear that I'm not trying to peer into a user's calendar and read their darkest secret appointment titles, but I would still like to be able to show that this person is unavailable during that time. For example in Outlook proper it just shows as "Private Appointment" - which is exactly what I want to be able to do in my app.
Here's the code I've got for scraping the user's calendar:
private Calendar CreateCalendar(String User_Name, String Initials, DateTime Week)
{
string filter = "[Start] >= '"
+ Week.ToString("g")
+ "' AND [End] <= '"
+ Week.AddDays(7).ToString("g") + "'";
Microsoft.Office.Interop.Outlook.Application App = new Microsoft.Office.Interop.Outlook.Application();
Microsoft.Office.Interop.Outlook.NameSpace mapiNamespace = App.GetNamespace("MAPI");
//Resolve the person whose calendar We're trying to read.
Outlook.Recipient rm = App.Session.CreateRecipient(User_Name);
if (rm.Resolve())
{
try
{
Outlook.Folder calFolder = App.Session.GetSharedDefaultFolder(rm, Outlook.OlDefaultFolders.olFolderCalendar) as Outlook.Folder;
Outlook.Items CalItems = calFolder.Items;
CalItems.IncludeRecurrences = true;
CalItems.Sort("[Start]", Type.Missing);
//Search for Items within the pre-defined time range.
Outlook.Items restrictItems = CalItems.Restrict(filter);
if (restrictItems.Count == 0)
{
Debug.Print("No Items Found");
return new Calendar(User_Name, Initials);
}
else
{
//Create our internal representation of their calendar, for use elsewhere.
Calendar cal = new Calendar(User_Name, Initials);
Outlook.AppointmentItem i = (Outlook.AppointmentItem)restrictItems.GetFirst();
do
{
cal.AddAppointment(i.Subject, i.Start, i.End);
i = restrictItems.GetNext();
} while (i != null);
App = null;
mapiNamespace = null;
return cal;
}
}
catch (Exception ex)
{
App = null;
mapiNamespace = null;
throw new AccessViolationException(User_Name + " was resolved but could not access their calendar. Have they set you up as a delegate?", ex);
}
}
else
throw new AccessViolationException("The name " + User_Name + " was not resolved, make sure their name in the RM List is spelled correctly. If you can enter their name as a recipient in an outlook mail message and it resolves correctly when you click 'Check Names', then it should work!");
}
I'm not sure if private events are contained in the same "Folder" in outlook's data structures, so maybe I'm just not looking in the right spot?
I've been having trouble googling this because "private" is a reserved word in C# that basically hits on every single post with code and a function declaration in it. Hopefully you guys will be more helpful.
Thanks!
I have 2 accounts added to outlook , two seperate pst files. You will get clear idea with image below :
First i prompt user select folders from the outlook which ones to read, image attached for better understanding:
At the end i have the folderpaths in a list, same as in the image.
Now i want to read emails only from these specific paths and send them replies or delete them, so how can i do that?How can i read the folder based on a path n such way i get the account associated with it so i can also send emails using that accounts.
Use the following code to loop through all the folders then match the path with the ones in the list.
CODE:
OutLook.Application oApp = new OutLook.Application();
OutLook.NameSpace oNS = (OutLook.NameSpace)oApp.GetNamespace("MAPI");
oNS.Logon(Missing.Value, Missing.Value, false, true);
foreach (OutLook.MAPIFolder folder in oNS.Folders)
{
string folderName = folder.Name;
GetFolders(folder);
}
public void GetFolders(MAPIFolder folder)
{
if (folder.Folders.Count == 0)
{
string path = folder.FullFolderPath;
if (foldersTocheck.Contains(path))
{
//GET EMAILS.....
foreach (OutLook.MailItem item in folder.Items)
{
Console.WriteLine(item.SenderEmailAddress + " " + item.Subject + "\n" + item.Body);
}
}
}
else
{
foreach (MAPIFolder subFolder in folder.Folders)
{
GetFolders(subFolder);
}
}
}