1

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.

Matt
  • 13,833
  • 2
  • 16
  • 28
user3486773
  • 1,174
  • 3
  • 25
  • 50
  • I don't believe SSIS can natively open and download attachments from an email (or open emails at all), but you may want to check out Task Factory since it adds this functionality: http://pragmaticworks.com/Products/Task-Factory – Ryan Intravia Sep 21 '16 at 16:58
  • 1
    Wondering if there's a way to use a rule to achieve it. Worst case scenario create a small c# service/app that talks to exchange web services – Charleh Sep 21 '16 at 16:59
  • @Charleh there is not native rule to do it, but based on this link which may be a out of date http://www.pixelchef.net/content/rule-autosave-attachment-outlook it shows that the VBA code to create a rule that will do it is pretty easy. The only problem with this route would be this would be a desktop not a server side rule so his/her email would have to be open at the correct time. – Matt Sep 21 '16 at 17:11

1 Answers1

2

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.

Matt
  • 13,833
  • 2
  • 16
  • 28
  • This is more than just a start! Thank you so much for the direction. – user3486773 Sep 21 '16 at 22:09
  • Your welcome I got curious about my old solution so I dug it back up and read through it. – Matt Sep 22 '16 at 00:16
  • Interestingly, I use the same sort of thing to scan an email box for backup alerts (to manage backups alerts for a shedload of clients). Works a treat, even when we switched from on-prem exchange to O365 – Charleh Sep 22 '16 at 10:35
  • @Charleh I originally developed to fix a bug with an email feedback loop that I was stuck with for ~1 year before Email Service Provider Fixed. so I had built it to process a few thousand returned messages at a time to determine if they should be ignored (out of office), email address changed, or forwarded to our customer service to take care of the issue... It did great in Office 365 I never quite got the on prem working with it but it is supposed to..... definitely pretty scale able though as I think overall my little app processed about 300-500K messages overall and ~1K/1-2min – Matt Sep 22 '16 at 15:42
  • Just wanted to add that I was able to successfully implement this using 98% of your solution with 2% tweaking. So I have an ssis job that now runs a script task and can grab an excel file, save it, then data flow task it into my DB! Thanks again! – user3486773 Sep 29 '16 at 16:20
  • @user3486773 awesome glad it worked. let me know about the 2% that needed tweaked if there was some error or updated code I am missing so I can integrate. Cheers – Matt Sep 29 '16 at 16:22
  • Well runs from my machine, but not the scheduling server... Any ideas? – user3486773 Sep 29 '16 at 21:40
  • is the Exchange Web Services (EWS) Managed API installed on the server that is actually executing the package? – Matt Sep 29 '16 at 21:43
  • So installed EWS 64 bit on 64 bit scheduling server, still no luck. – user3486773 Sep 30 '16 at 19:59
  • @user3486773 Do you have any errors that you can share? did the server get rebooted after install (not sure if that is required or not)? Are there any firewalls that are blocking traffic from scheduling server to internet/office 365? what os is scheduling server and is SSIS and SQL server installed? you should probably post another question saying this code works from dev environment but not production include configurations and errors then more than just I will be looking at it – Matt Sep 30 '16 at 20:15