Cannot Access Attachment Data From Embedded Attachment
-
Thursday, June 10, 2010 6:03 PM
I am writing a VB.NET windows forms application, I need to read the binary data in all attachments for a given message. I have a Microsoft.Office.Interop.Outlook.MailItem object that contains the mail Item with the attachments. I get an error when I try to save the attachment to a file using Attachment.SaveAsFile if the attachment is embedded.
Dim Att as Microsoft.Office.Interop.Outlook.Attachment
For Each Att in MyMailItem.Attachments
Att.SaveAsFile("c:\test\" & Att.FileName)
Next
The aboce code seems to work fine for any file attached to the MailItem, However if I insert a picture in the e-mail body the Att.SaveAsFile returns the error System.Runtime.InteropServices.COMException (0x80004005): Cannot save the attachment. Cannot add the attachment; no data source was provided.
at Microsoft.Office.Interop.Outlook.Attachment.SaveAsFile(String Path)
All Replies
-
Thursday, June 10, 2010 6:22 PMModeratorI can't duplicate the problem here. What's the value of Att.FileName for the attachment in question? Does it duplicate the name of a file already in the target location?
-
Thursday, June 10, 2010 7:48 PM
Sue,
The target location is a empty directory so it cannot be a duplicate, the value of Att.FileName is image003.jpg,
Here is the code I am using
In a windows form command button click event
Dim ol As New OutlookInterface
ol.ToAddress = "test@test.com"
ol.Subject = "Test Subject"
ol.Body = "Test Body"
ol.BodyIsHTML = False
ol.ShowSendMailDialog()
If Not ol.MailSent Then Exit SubIn a seperate class
Imports System.Diagnostics
Imports System.Linq
Imports System.Reflection
Imports System.Runtime.InteropServices
Imports Outlook = Microsoft.Office.Interop.Outlook
Public Class OutlookInterface
Private Shared OutlookApplication As Outlook.Application
Private WithEvents MyMailItem As Outlook.MailItem
Public ToAddress As String
Public FromAddress As String
Public Subject As String
Public Body As String
Public BodyHTML As String
Public BodyIsHTML As Boolean
Public MailSent As Boolean = FalsePrivate Sub Mail_Send(ByRef Cancel As Boolean) Handles MyMailItem.Send
Try
ToAddress = MyMailItem.To
Subject = MyMailItem.Subject
Select Case MyMailItem.BodyFormat
Case Outlook.OlBodyFormat.olFormatPlain
BodyIsHTML = False
Case Outlook.OlBodyFormat.olFormatHTML
BodyIsHTML = True
Case Outlook.OlBodyFormat.olFormatRichText
BodyIsHTML = True
Case Outlook.OlBodyFormat.olFormatUnspecified
BodyIsHTML = False
End Select
Body = MyMailItem.Body
BodyHTML = MyMailItem.HTMLBody
Dim Att As Outlook.Attachment
For Each Att In MyMailItem.Attachments
Debug.Print("Attachment Index=" & Att.Index)
Debug.Print("Attachment FileName=" & Att.FileName)
Debug.Print("Attachment DisplayName=" & Att.DisplayName)
Debug.Print("Attachment PathName=" & Att.PathName)
Try
Att.SaveAsFile("c:\test\" & Att.FileName)
Catch ex As Exception
MsgBox("Error Saving Attachment ex=" & ex.ToString)
End TryNext
MailSent = True
Debug.Print("Mail Sent!")
Catch ex As Exception
MsgBox("Outlook Interface Error @ Mail_Send Ex=" & ex.ToString )
End TryEnd Sub
Private Sub Mail_Close(ByRef Cancel As Boolean) Handles MyMailItem.Close
Debug.Print("Mail Close!")
End SubPrivate Shared Function LogOnOutlook() As Boolean
Try
'Check if there is an Outlook process running.
If Process.GetProcessesByName("OUTLOOK").Count() > 0 Then' If so, use the GetActiveObject method to obtain the process and cast it to an Application object.
OutlookApplication = DirectCast(Marshal.GetActiveObject("Outlook.Application"), Outlook.Application)
Else' If not, create a new instance of Outlook and log on to the default profile.
OutlookApplication = New Outlook.Application()
Dim ns As Outlook.NameSpace = OutlookApplication.GetNamespace("MAPI")
ns.Logon("", "", Missing.Value, Missing.Value)
ns = Nothing
End If' Return the Outlook Application object.
Return True
Catch ex As Exception
MsgBox("Outlook Interface Error @ LogOnOutlook ex=" & ex.ToString)
Return False
End TryEnd Function
Public Function ShowSendMailDialog() As Boolean
If OutlookApplication Is Nothing Then
If Not LogOnOutlook() Then Return False
End IfTry
' Create a new MailItem and set the To, Subject and Body properties.
MyMailItem = DirectCast(OutlookApplication.CreateItem(Outlook.OlItemType.olMailItem), Outlook.MailItem)
MyMailItem.To = ToAddress
MyMailItem.Subject = Subject
If BodyIsHTML Then
MyMailItem.BodyFormat = Outlook.OlBodyFormat.olFormatHTML
MyMailItem.HTMLBody = BodyHTML
Else
MyMailItem.BodyFormat = Outlook.OlBodyFormat.olFormatPlain
MyMailItem.Body = Body
End If
MyMailItem.Display(True)
Return MailSent
Catch ex As Exception
MsgBox("Outlook Interface Error @ ShowSendMailDialog ex=" & ex.ToString )
Return False
End TryEnd Function
End Class
When you click on the windows form button, a new mail item window is shown, change the mail format to HTML then insert a picture into the body then click send -
Thursday, June 10, 2010 8:01 PMModeratorThe problem may be that you're messing with the attachments during the Send event. What exactly are you trying to accomplish? Not the programming logic, but the business or productivity goal? Knowing that may help us give you ideas on a more reliable approach.
-
Thursday, June 10, 2010 8:23 PM
Sue,
The goal here is to allow the user to send a e-mail message from our application, then we want to save a copy of the entire message including attachments in our database so that we can later display the message using a WebBrowser control and allow the user to retrieve the attachments.
The reason I am accessing the MailItem properties durring the Send Event is because after the MyMailItem.Display(True) returns, the mail item is no longer accessable and returns the error "The item has been noved or deleted."
-
Thursday, June 10, 2010 8:50 PMModerator
I didn't notice you were displaying the Inspector modally. That's generally not recommended.
The best point in the process for saving a copy of the entire message is after the item has been transmitted to the outbound server and arrives in the Sent Items folder. Complete information about the sender and transmission time and account won't be available until then. You might consider combining your current application with an Outlook add-in that can watch the Sent Items folder with the Folder.Items.ItemAdd event handler, as transmission may not occur until sometime after the user clicks Send.
- Marked As Answer by Ji.ZhouModerator Tuesday, June 22, 2010 9:54 AM
-
Monday, June 14, 2010 9:34 AMModerator
Hi,
I am writing to check the status of the issue on your side. Could you please let me know if the suggestion works for you or not? If you have any questions or concerns, please feel free to let me know. I will be more than happy to be of assistance.
Tim Li
MSDN Subscriber Support in Forum
If you have any feedback on our support, please contact msdnmg@microsoft.com
Please remember to mark the replies as answers if they help and unmark them if they provide no help. -
Friday, December 07, 2012 6:47 AM
Hi,
I am facing the exact same problem in C#.
My business requirement is that I need to encrypt my emails(any material/content/attachments etc.) before really sending to the destination. So having limitations, that I have to do the the work only at sending event time.
Also facing another problem, although I searched a lot, but did not find any solution, that I could not detect the attachment type, either it is regular attachment or embeded one. all attachments give Type property as olByValue. Is there any good way provided to find actual attachment type.
Looking for the solution or any workaround to get the task done.
-
Friday, December 07, 2012 8:19 AMItemSend is the only event that suits your needs (beside providing your own button for sendign mail). Cancel sending, copy message, do your encryption and send your message. As for attachment type, you can check PrAttachFlags http://schemas.microsoft.com/mapi/proptag/0x37140003 and ContentId http://schemas.microsoft.com/mapi/proptag/0x3712001E using PropertytAccessor
-
Wednesday, December 12, 2012 5:43 AM
Thanks DamianD,
Sure, I am working on ItemSend event, but the problem is that I could encrypt the regular attachment files smoothly but unable to encrypt embedded attachments due to following problems:
- I could not detect attachment type. (BTW the links you provided are seems not working. still in question?)
- Even if I detect somehow, these attachments are not physically exists, so how could I encrypt these because for encryption I need Stream object loaded with attachment data)
- I could not detect attachment type. (BTW the links you provided are seems not working. still in question?)
-
Wednesday, December 12, 2012 7:16 AM
ad 1. those are not links, they are ids that you provide in PropertyAccessor.Getproperty method, look at http://msdn.microsoft.com/en-us/library/office/bb207521(v=office.12).aspx
ad 2. if your plugin should encrypt _only_ attachments and leave mail body intact, then simply omit those embedded attachments, they are usually used for in-place pictures and such stuff, encrypting them would only break visual look of mail's body.
-
Thursday, December 13, 2012 11:53 AM
Thanks DamianD for quick support. I am getting following error, while trying attachment.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x37140003")
The property "http://schemas.microsoft.com/mapi/proptag/0x37140003" is unknown or cannot be found.
while other property return empty string for attached files.
Secondly, I also need to encrypt the body content, simple html content is encrypted but embedded pictures are creating the problem. Yes rightly said that it is breaking the visual look of the mail's body but for targeted email it is compromised because security is top concern in my scenario.
-
Thursday, December 13, 2012 2:27 PM
you have to be prepared to catch exceptions for Getproperty, this is how it is. As for second part - if you need to enrypt everything, why don't you use builtin functionality in outlook for this? Outlook allows to create digitally signed and/or encrypted mails, provided you have target person certificate with public key imported into contacts or few other means. Is that acceptable for you? if not, thenb you should try to mimic standards as much as possible which means grabbing whole mail as is (attachments, body, everthing) and storing it into single encrypted attachments which you can decrypt on other side. Depending on your skills in programming, you can do it from MAPI level (copying MAPI properties/streams from enccypted attachment) or you can simply same whole mail as msg, encrypt it, create empty new mail, add recipients and subject and send that encrypted msg as attachment and on the other side reverse whole process, adding msg file to inbox.
-
Monday, December 17, 2012 6:55 AM
Thanks a lot DamianD.
OK, properties are seems working in my scenario (with catching exceptions), but I suggests there should be some better reliable method for this purpose by Microsoft.
For some business requirements I have to follow my custom encryption methods and outlook built-in functionality does not fit in this scenario. Any how Your suggestion is quite practical that I have to mimic the standards and encrypt the whole message as single entity and then reverse the process for other side.
Thanks again for your support.

