Search code examples
c#outlookoffice-interopemail-attachmentsvspackage

Zipping outlook attachment on the fly


I'm developing a Visual Studio extension that adds a command to VS to compose a message in Outlook with an attachment. The attachment is simple .csv file that is also produced by the extension. So when user fires the command, outlook opens a window with an email already composed and attachment added. The user might just click send.

Now I've been asked to add possibility to send those logs compressed with zip. I would like to compose a message with an attachment already compressed, but I don't want any temporary .zip files retained after message is sent (or cancelled). How can I achieve this?

My code that composes the message and opens Outlook window:

using Microsoft.Office.Interop.Outlook;

...

    private static bool TrySendMethod1(string subject, string toAddr, string body, string logPath)
    {
        try
        {
            Application app = new Application();
            MailItem mailItem = app.CreateItem(OlItemType.olMailItem);
            mailItem.Subject = subject;
            mailItem.To = toAddr;
            mailItem.Body = body;
            if (logPath != null) mailItem.Attachments.Add(logPath);
            mailItem.Importance = OlImportance.olImportanceNormal;
            mailItem.Display(false);
            return true;
        }
        catch (System.Exception e)
        {
            return false;
        }
    }

update Once the email is composed, an outlook window with a composed message is displayed (it has the attachment already set). Now, the user might just send it, cancel it or whatever. He might even leave the window opened for hours (although this is not common) and then send it (even after VS has been closed). Again, i don't want any temporary archives to exist on the disk after the message is sent or cancelled.

I added full method that sends the email. It's not much more, but this method is just invoked when user selects a new Visual Studio command that my extension adds to it (tools -> send TFS logs -> from this month). There just an additional method between button handler and it simply sets some parameters for the one presented here (sets the subject, logPath and so on...)

If it's not possible, then I can also accept such an answer.


Solution

  • You can compress a file using this:

    public static void Compress(FileInfo fileToCompress, string compressedFileName)
    {
        using (FileStream originalFileStream = fileToCompress.OpenRead())
        {
           using (FileStream compressedFileStream = File.Create(compressedFileName)
                {
                    using (GZipStream compressionStream = new GZipStream(compressedFileStream, CompressionMode.Compress))
                    {
                        originalFileStream.CopyTo(compressionStream);
                    }
                }
        }
    }
    

    Modified from: http://msdn.microsoft.com/en-us/library/ms404280(v=vs.110).aspx

    For deleting the file afterwards you can attach to the MailItem.Unload Event.

    This event occurs after the Close event for the Outlook item occurs, but before the Outlook item is unloaded from memory, allowing an add-in to release any resources related to the object. Although the event occurs before the Outlook item is unloaded from memory, this event cannot be canceled.

    Source: http://msdn.microsoft.com/en-us/library/office/ff868564(v=office.15).aspx

    Then you TrySendMethod1 could look like this

    private static bool TrySendMethod1(string subject, string toAddr, string body, string logPath)
    {
        try
            {
              Application app = new Application();
              MailItem mailItem = app.CreateItem(OlItemType.olMailItem);
              mailItem.Subject = subject;
              mailItem.To = toAddr;
              mailItem.Body = body;
              string compressedFileName = logpath + ".gz";
              CompressedStack(logpath, compressedFileName);
              if (logPath != null) mailItem.Attachments.Add( compressedFileName );
              mailItem.Importance = OlImportance.olImportanceNormal;
              mailItem.Display(false);
              mailItem.Unload += (e) => {File.Delete(compressedFileName);};
              return true;
          }
          catch (System.Exception e)
          {
              return false;
          }
      }
    

    Exception handling for the File.Delete is missing, and I am not sure 100% certaing about the signature of the Unload event, but have a try and let us know.

    This will NOT handle the case where Visual Studio is closed BEFORE the mail is sent! (I think that might not even be possible.)