I receive an email with an excel file every week. I know there are probably better ways to accomplish my goal, but would it be possible to have a script task in SSIS that can open email, look for a specific file name as an attachment and then copy that file to another location?
Here is the scenario. This excel file is important for my team to have in a SQL database, and the provider of the excel source is only willing to email this excel file to us once per week. I then check my email, copy the file to a location where an SSIS dataflow task can then pick it up and insert it into a SQL table. I would like to automate this. So if my original approach is not doable, how else could this be automated? Aside from using a shared network location. Assume the excel file can ONLY come from the email. Using outlook/office 365, SSIS, SSMS, I have DBO access, and can use c#.
I'll admit that I'm ignorant on the email. If there is a procedure that the email client can actually execute to accomplish this, then I'd be all ears!
EDIT: I also have access to a network drive as I realize saving to my local machine may be impossible.
Simple Answer Yes it is Possible.
I had written a console program to process email on Office365 that I was also interfacing with SQL, so it definitely can be done. It isn't necessarily the easiest thing in the world but it is not too hard either.
You can use the Exchange Web Services (EWS) Managed API
Article on stating it is possible and the API documentation
https://msdn.microsoft.com/en-us/library/office/dd877012(v=exchg.150).aspx
Github location where you can find the API (note this link is directly form Microsoft's Site)
https://github.com/officedev/ews-managed-api
Link on how to reference the assembly which contains the second link above:
https://msdn.microsoft.com/en-us/library/office/dn528373(v=exchg.150).aspx
Create and Connect to Service
string emailAddress = 'YourEmail#Domain.com';
ExchangeService exService = new ExchangeService(ExchangeVersion.Exchange2013_SP1);
exService.Credentials = new WebCredentials(emailAddress,"password");
you can autodiscover or if you know the URL just set it so 1 of these lines
exService.AutodiscoverUrl(_emailAddress, delegate { return true; });
exService.Url = new Uri("https://outlook.office365.com/EWS/Exchange.asmx");
Find your Inbox & a Folder to Move the File To After Being Processed:
FolderView folderView = new FolderView(1);
folderView.PropertySet = new PropertySet(BasePropertySet.IdOnly);
folderView.PropertySet.Add(FolderSchema.DisplayName);
folderView.Traversal = FolderTraversal.Deep;
SearchFilter searchFilter = new SearchFilter.IsEqualTo(FolderSchema.DisplayName, "ProcessedFolderName");
Folder Inbox = Folder.Bind(exService, WellKnownFolderName.Inbox);
FindFoldersResults folderResults = Inbox.FindFolders(searchFilter, folderView);
FolderId processedFolderId = folderResults.Folders[0].Id;
Find Messages That meet your criteria:
List<SearchFilter> searchFilterCollection = new List<SearchFilter();
searchFilterCollection.Add(new SearchFilter.ContainsSubstring(ItemSchema.Subject,"Words in Subject"));
searchFilterCollection.Add(new SearchFilter.IsEqualTo(ItemSchema.HasAttachments,true));
searchFilterCollection.Add(new SearchFilter.IsEqualTo(EmailMessageSchema.From,new EmailAddress("From#SendersDomain.com")));
SearchFilter searchFilter = new SearchFilter.SearchFilterCollection(LogicalOperator.And,searchFilterCollection);
ItemView view = new ItemView(50, 0, OffsetBasePoint.Beginning);
view.OrderBy.Add(ItemSchema.DateTimeReceived, SortDirection.Descending);
view.PropertySet = new PropertySet(BasePropertySet.IdOnly, ItemSchema.DateTimeReceived, ItemSchema.Attachments);
view.Traversal = ItemTraversal.Shallow;
FindItemsResults<Item> findResults = exService.FindItems(WellKnownFolderName.Inbox,searchFilter,view);
Process the results and save the attachments when done move the message to another folder so you don't keep importing the same one.
foreach (Item i in findResults.Items)
{
foreach(FileAttachment attachment in i.Attachments)
{
attachment.Load(#"\\FilePathDirectory\" + attachment.FileName);
}
i.Move(processedFolderId);
}
you can expand the solution by testing if you get no results sending yourself an error message or throwing an error for SSIS to pickup and fail the job. It is likely that you will overwrite the file multiple times if you have multiple messages to process so you may consider adding something unique in the file name instead of just using the same one but that will present other challenges in SSIS as well.
anyway, its a start hope it helps.
Related
I have a solution I created a little over a year ago that uses PnP.Core to upload file to a specific folder on SharePoint. It was all well until a couple days ago where that solution started generating error that says
To update this folder, go to the channel in Microsoft Teams
I am at a bit of a loss as to why and what is causing this.
Below is a minimal code sample of what I have. I should mention that the folder is getting created but fails with said error when uploading the file to the folder.
Any pointers would be greatly appreciated.
authenticate using officeDev.PnP.Core.AuthenticationManager
...
Folder Root_Folder = web.GetFolderByServerRelativeUrl(Root_Folder_Relative_Url_Path);
//Create new subFolder to load files into
string Folder_Name = _Folder_Name;
Root_Folder.Folders.Add(Folder_Name);
Root_Folder.Update();
//Add file to new Folder
Folder Subject_Folder = web.GetFolderByServerRelativeUrl(Root_Folder_Relative_Url_Path + "/" + Folder_Name);
FileCreationInformation Subject_Result_File = new FileCreationInformation {
ContentStream = new MemoryStream(_File_To_Upload),
Url = _File_Name,
Overwrite = true
};
Microsoft.SharePoint.Client.File uploadFile = Subject_Folder.Files.Add(Subject_Result_File);
Subject_Folder.Update();
Client_Ctx.ExecuteQuery();
Looks like the Update method was the issue. Removing it and just letting the ExecuteQuery handle all the operation fixed it.
I'm trying to add folder to inbox as follows:
var _client = new ImapClient();
_client.Connect(hostName, portNumber, useSsl);
_client.Authenticate(username, password);
_client.Inbox.Open(FolderAccess.ReadWrite);
_client.Inbox.Create("Name", true);
Everything goes fine, the Create function returns created folder, the _client.Inbox.GetSubfolders() returns list that contains new created folder as well, however I can't see this folder in e-mail client application (such as Thunderbird).
What am I doing wrong?
Thunderbird may only be showing you subscribed folders. If that is the case, then you will also want to do newFolder.Subscribe ();
I should also point out that there's no reason to Open() the inbox before creating a child folder.
You only need to Open() a folder in order to read messages from it.
I'm new with C# and i'm making one *.exe that have to search emails with a specific subject in my Exchange.
For Inbox and Other Folders i use the code bellow (with no problems):
FindFoldersResults allEmailFolders_Inbox = service.FindFolders(WellKnownFolderName.Inbox, new FolderView(int.MaxValue) { Traversal = FolderTraversal.Shallow });
FindFoldersResults allEmailFolders = service.FindFolders(WellKnownFolderName.Inbox, new FolderView(int.MaxValue) { Traversal = FolderTraversal.Deep });
Now i'm trying to search inside Sent Item Folder, but don't return me results. If i make a new folder inside SentItems the email apeears, but inside Sent items no. I try the code bellow:
FindFoldersResults allEmailFolders_Sent = service.FindFolders(WellKnownFolderName.SentItems, new FolderView(int.MaxValue){Traversal=FolderTraversal.Deep});
FindFoldersResults allEmailFolders_Sent = service.FindFolders(WellKnownFolderName.SentItems, new FolderView(int.MaxValue){Traversal=FolderTraversal.Shallw});
Can someone help me?
The lines of code you've shown are searching for folders inside the inbox or inside the sent items folder, not email. You might want to take a look at the Search topics in MSDN: https://msdn.microsoft.com/EN-US/library/office/dn579421(v=exchg.150).aspx. There are links to a number of search samples there as well. This one seems relevant to your scenario: https://code.msdn.microsoft.com/exchange/Exchange-2013-Search-for-2ea5597e/sourcecode?fileId=84155&pathId=889776652
I have 3 data files:
Outlook data file (is empty)
Gmail data file (from my gmail pop3)
Yahoo data file (from my yahoo imap)
I can access the Outlook data file inbox (which is always empty, I don't know how to automatically move from my google and yahoo account to my outlook data file) with
this code:
Outlook.MAPIFolder inBox = (Outlook.MAPIFolder)this.Application.
ActiveExplorer().Session.GetDefaultFolder
(Outlook.OlDefaultFolders.olFolderInbox);
I have 2 questions:
How can I make my gmail and yahoo account automatically move to my outlook data file?
How to code to access my inbox in my gmail and yahoo account?
I have tried this function to make return to my MAPIFolder:
public Outlook.MAPIFolder GetInbox(string userName)
{
Outlook.Application oOutlook = new Outlook.Application();
Outlook.NameSpace oNs = oOutlook.GetNamespace("MAPI");
Outlook.Recipient oRep = oNs.CreateRecipient(userName);
Outlook.MAPIFolder inbox = oNs.GetSharedDefaultFolder(oRep, Outlook.OlDefaultFolders.olFolderInbox);
return inbox;
}
But it didn't work. help me pleaseee..
I'm not sure I understand your first question, would you like to join all the data files into the main outlook data file?
About your second question, Outlook data files are represented by stores in the API, and if you call GetDefaultFolder on the Session object, you'll always end up with getting the default store's default folder (Inbox of your Outlook data file).
You can list all the store files and use GetDefaultFolder on them to retrieve the inbox folders for each store/data file:
Outlook.Stores stores = this.Appliction.Session.Stores;
foreach( Store store in stores )
{
Outlook.Folder inboxOfStore = store.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
//Do stuff with your inbox folder.. Check store properties for infomation on which data file this store represents
}
See documentation for more information:
http://msdn.microsoft.com/en-us/library/office/bb176405%28v=office.12%29.aspx
I'm facing a problem with an Internet application I'm working on right now (programming in C#).
I have to create a report and then send it via email to a certain user. After I create the report, I save it first into a temporary file, then attached it to the email giving the file path.
It's working on my computer because I have the administrator right, but it doesn't for my coworkers who don't have the admin right on their computer.
The file path I'm using is:
string filePath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.InternetCache),
fileName
);
Is there any temporary repository I can use that doesn't require admin rights?
Thanks.
Considering your ASP.NET tag, you should look at using Isolated Storage.
If you're using the built in mail classes in .Net, there's really no reason you need to write the attachment to a file at all, unless whatever is generating the report requires it.
This would work, assuming your report generator doesn't require file output and can just return bytes.
SmtpClient smtpClient = new SmtpClient(); //do whatever else you need to do here to configure this
byte[] report = GetReport();//whatever your report generator is
MailMessage m = new MailMessage();
//add your other mail fields (body, to, cc, subject etc)
using (MemoryStream stream = new MemoryStream(report))
{
m.Attachments.Add(new Attachment(stream,"reportfile.xls"));//just guessing, use the right filename for your attachment type
smtpClient.Send(m); //note that we send INSIDE this using block, because it will not actually read the stream until you send
//and you want to make sure not to dispose the stream before it reads it
}
How are you attaching it to the email? From the sounds of your question it appears that all you're doing is giving them the path to the file you create, rather than attaching it (as, once you attach it, it's embedded in the email and thus there are no paths involved).
If the web application is creating the temporary file then you can use the app_data folder (which is usually writable), and get a unique file name by using Path.GetRandomFileName().
So, something like
var myTemporaryFileName = Path.Combine(HttpContext.Current.Server.MapPath("~/App_Data",
Path.GetRandomFileName());
Then write your file to this temporary file name, then attach it to the email
MailMessage message = new MailMessage("recipient#example.com", "", ""
"subject",
"mail body");
Attachment data = new Attachment(file, MediaTypeNames.Application.Octet);
ContentDisposition disposition = data.ContentDisposition;
disposition.FileName = "thefilenameyouwanttouseintheemail.ext";
message.Attachments.Add(data);
Now you can send it.
Don't forget to clean them up after though!