All properties available from a VSTO Outlook AdvancedSearch - vsto

I'm using VSTO with Outlook 2007, in c#. I can execute an Outlook.Application.AdvancedSearch(), and get a table. I want to select the columns to access from the table using Outlook.Table.Columns.Add(). I can't seem to find a complete list of property names that I can pass to Add() (I'm only interested in mail items). I've guessed a few of the obvious ones (ReceivedTime, SenderEmailAddress, To, Subject, Body, EntryID). I was hoping to be able to get the (plain text) body of each email, but trying to add the property Body doesn't seem to work. Is it impossible to get Body as a column, or is it just under a different name?

The page Unsupported Properties in a Table Object or Table Filter says that Body should work for the first 255 bytes. That didn't work for me, but even if it did, that's not what I want. Thus, I get the EntryID property, then use mapiNameSpace.GetItemFromID(entryId, Type.Missing) to get the MailItem object, and get the (entire) plain-text body from MailItem.Body.

Related

MS Access | How to get content from mail body to table?

I am working on a project where I need to get ms access table/data from mail body and execute some command in SAP. I can manage SAP part but issue is that how to get information from mail body. i tried linking my mailbox in access but it shows me all mail body text but i need some specified contents only. example
Hello,
Please supplement budget
WBS Amt
N.10002077.001 1
from above what i need is just "N.10002077.001" and "1" ,but how to get that information only in table is the issue?
Further, what I will get in my mail will be table with 2 column but access imports it as a simple text.
It is impossible to give a definite answer to your question because it is too vague but it is possible to get you started.
Have a look at this answer of mine: https://stackoverflow.com/a/12146315/973283. The question is not relevant other than the OP did not understand that showing screenshots told us little about what the body looked like to a VBA macro. The answer includes a macro that copies selected properties from every email in Inbox to an Excel worksheet. This will allow you to see what an email’s body looks like to a VBA macro.
How will you identify the emails from which you wish to extract data? The two simple choices are:
Look at every email in a folder and identify the interesting one by examining the subject, sender or some other property.
Select the interesting emails then run a macro which uses ActiveExplorer to access the selected emails.
The answer referenced above demonstrates technique 1. There are lots of answers demonstrating technique 2 but I can add an example macro if necessary.
An email typically has an Html body and a text body. If an email has an Html body, that is the one shown to the user. A macro can access either or both. Your screen shot looks like a text body although appearances can be deceptive. If it is a text body, the email does not have an Html body.
If it is a text body, the layout of the body is probably something like:
Hello,{cr}{lf}
Please supplement budget{cr}{lf}
WBS{tab}{tab}{tab}{tab}{tab}Amt{cr}{lf}
N.10002077.001{tab}{tab}1{cr}{lf}
This assumes, the sender has used variable numbers of tabs to line up the columns.
You could use Split on vbCr & vbLf to convert the string body into an array of strings with one line per array entry. Discard lines up to and including the line starting “WBS” then process each line down to any signature. Split each line on vbTab and expect to find two entries with values with the rest blank.
See how far you can get with the above hints then clarify your answer if you need more information.

How can I build custom Word fields with VBA

I've found a question in stackoverflow: "How can I build Word fields with VBA" by JonnyGold.
I'm interested in the same question, but possibly on other reasons. The answers to JonnyGold question doesn't satisfy me. I'm still in MS-word 2003. My problem is to construct a custom word field, which would recognize a bookmark name around cursor location, saves that name in some custom variable/property, so that in a case of need a hyperlink of ref field could return a cursor to the said bookmark.
I need that mechanism to facilitate an easy work with a list of bibliographic sources, so that a user can by one click to go from a reference to a source and then to return back. Note that one source could be referenced in several different places and a user should be able to return to a reference, he/she clicked before.
I tried to use REF field with MACROBUTTON field inside, but MACROBUTTON requires double or one click on a button/text, which I want to avoid. I would like to create a field {RUNMACRO MacroName}, which would run a specified VDA Macro.

Microsoft Word VBA - IF & THEN Find word and print in another sheet

I am a bit of novice when it comes to VBA (mostly navigate through the code by Recording actions and then altering it accordingly to what I need).
My current problem is the following:
I am going to compile hundreds of word Docs that contain email addresses from clients that I need. In order to make this as easy as possible, I would like to have some code that finds their emails AND additional information that surrounds the email addresses (Name, Location,Job Title,and [possibly] Phone Number) and then copies and pastes the mentioned info to another designated document. The documents and the abovementioned info are formatted as such :
FirstName LastName
Location
Job title # Company
email address - phone number
Now, I believe this will include and IF/THEN statement since not all clients have their email addresses in the documents.
So, IF there is an email address THEN copy it along with the 3 lines above and the phone number that is separated by "a space" "-" "a space"AND paste it on another sheet. IF there is no email address, then keep going.
This query code will probably include a FIND that needs to have a "#" and ".com" attached to the same string. This will be needed since the document also includes other text that has ".com" and "#" but not together.
This sounds harder than what it really is, but again I'm a novice so not completely sure. Feel free to ask any additional questions!
This is an extremely broad question, but I suggest you do the following:
Use a Scripting.FileSystemObject to iterate through files in a folder, looking for Word documents
Open the document using the Word Automation object model
Application object
Application.Documents property, and Documents collection
Documents.Add method, and the Document object, to create the destination document
Documents.Open method, to open existing documents
Find emails within the document (via the Document.Content property, and the Range object)
Range.Find property and the Find object
If the Find.Execute2007 method returns true, then:
Extend the range to the previous 3 paragraphs
Range.MoveStart method
Copy and paste the range to the destination document
You can write only the text to the destination document — Range.Text property, and the Range.Insert-* methods
Or, you can use the clipboard Range.Copy and Range.Paste
Or, you can export to an external file (Range.ExportFragment) and later import from the external file (Range.ImportFragment)

Excel VBA Search Outlook GAL Using ExchangeUser Alias Property

I am trying to search trough a 200,000 plus Outlook GAL using Excel VBA and the only thing I have as a search parameter is the alias property.
This can be done from the Outlook >> Address Book >> Advanced Find dialog and it returns a result quite fast.
I tried something like going trough each item, calling the ExchangeUser object and compare the Alias property against my search but it takes way to long.
The source is a monthly report that contains and ever changing Excel list of about 100 Aliases and each must be searched in an Outlook GAL with over 200,000 entries.
Is there a way to do it pragmatically from Excel that responds as fast as the outlook dialog?
You can
Use Application.Session.CreateRecipient / Recipient.Resolve and hope the alias resolves and there are no ambiguous entries. the search will be performed in all address book containers on the search path.
Use Extended MAPI (C++ or Delphi) to have a restriction to be applied to GAL. Note that only very particular restriction can be applied - you would need to open the PR_SEARCH property as IMAPIContainer, set PR_ALIAS property, call IMAPIContainer::GetSearchCriteria, then apply that criteria to the GAL contents table.
Use Redemption (any language, I am its author) - it exposes the RDOAddressListSearch object

Accessing inline and bar attachments

An Outlook message can contain attachments (see fig., borrowed from http://blogs.mccombs.utexas.edu/the-most/2011/01/28/email-attachments-in-the-body-of-outlook-messages/):
A set of inline attachments (IA, left fig.), understood as any object besides text
A set of bar attachments (BA, right fig.)
I have several questions on accessing them via VBA. They are cross-related, so it is worth posting them all together.
Is there a comprehensive way to access IA?
In many cases, I found that the collection MailItem.Inspector.WordEditor.InlineShapes (IS) is IS=IA. Is this always true?
Is there a comprehensive way to access BA?
In many cases, I found that the collection MailItem.attachments (AT) is AT=IA+BA. But I have found exceptions: emails with nonempty IA and empty AT. Some use of AT might perhaps help, even with what I found.
Having a reference to an item in IA, is there any way of knowing if there is a corresponding item in AT (there may be not, according to #2), and if so identify it, IA->AT?
Reversing the question in #3:
Having a reference to an item in AT, is there any way of inquiring if it is an InlineShape, and if so knowing which item in IA it corresponds to, AT->IA?
Is there any way of establishing the connections BA<->AT, similarly as in questions #3 and #4 for IA<->AT?
PS: I am using Outlook 2010, and according to http://www.msoutlook.info/question/261 and http://support.microsoft.com/kb/222330 that may bring about different results from Outlook 2007, etc.
Is there a comprehensive way to access IA? In many cases, I found that the collection MailItem.Inspector.WordEditor.InlineShapes (IS) is IS=IA. Is this always true?
NO. InlineShapes may contain items that you would not likely consider "attachments" per se, for instance, a corporate logo embedded in your signature, etc. will appear as an InlineShape which is not an "attachment" (although plain text email may include this as an attachment...)
Inline "Attachments" (inserted as object | create from file, for example) appear as Type = wdInlineShapePicture and they do not have an OLEFormat property (which surprises me...)
Is there a comprehensive way to access BA?
In many cases, I found that the collection MailItem.attachments (AT) is AT=IA+BA. But I have found exceptions: emails with nonempty IA and empty AT. Some use of AT might perhaps help, even with what I found.
Per my second comment, above, the inline shape "attachments" appear as wdInlineShapePicture but I believe they are treated as "attachments" in a roundabout way. Iterating the attachments collection you may notice items with generic names like "image002.png" I believe these are essentially "linked" through a metadata file (which may also show as an attachment item "oledata.mso", to another generically named attachment (like "image001.wmz". None of these attachments, which are part of the .Attachments collection, will appear as a "bar attachment".
The above screenshot comes from this email where I created a dictionary object to store the attachments by name (key). This email has 2 "bar attachments" and 2 "inline attachments". Note that the "bar attachments" are represented by their real "name", whereas the "inline attachments" are split in to the wmz/png files.
Having a reference to an item in IA, is there any way of knowing if there is a corresponding item in AT (there may be not, according to #2), and if so identify it, IA->AT?
I don't believe so. The "oledata.mso" file is not something that you can read or parse, as far as I'm aware, and this seems to be the only thing that connects the wmz/png files.
Reversing the question in #3:
Having a reference to an item in AT, is there any way of inquiring if it is an InlineShape, and if so knowing which item in IA it corresponds to, AT->IA?
No. As far as I can tell there is no "correspondence" between the inline shapes and the attachments. Even if you were to insert the same file as both an Attachment and an Object/InlineShape, these are separate and distinct items.
Here is another example email:
And the corresponding items in Attachments collection:
Is there any way of establishing the connections BA<->AT
Based on my research, possibly.
You can examine the HTML source of the email body, and parse out the inline shapes. Below you can see that the png/wmz from the last screenshot are present.
If you store ALL attachments in a dictionary object (assume m is a MailItem object):
Dim dictAttachments as Object
Set dictAttachments = CreateOBject("Scripting.Dictionary")
Dim attch As Attachments
Dim att as Attachment
Dim s as Integer
s = 0
Set attch = m.Attachments
For Each att In attch
Set dictAttachments(att.DisplayName) = att
s = s + 1
Next
Then if you have identified the png/wmz from the HTML Source, you can remove them from the dictAttachments object using the .Remove method.
dictAttachments.Remove("image001.wmz") 'etc.
Then, the dictionary object will contain only the "Bar Attachments".
The trouble with this (I have tried to do this now...) is that I'm not able to find a way to parse the HTML (using an HTMLFile object) to get the PNG -- it's in a part of the HTMLBody which is essentially commented out/conditionally rendered and so it does not respond to getElementsByTagName method, etc.
While I would always prefer to work with the HTML/XML objects (it's usually a bad idea to try and parse HTML with normal string functions), this may be a necessary exception. You could do something simply like:
Dim itm as Variant
For each itm in dictAttachments.Keys()
If Instr(1, m.HtmlBody, "cid:" & itm & "#") > 0 Then
dictAttachments.Remove(itm)
End If
Next
'Ignore the oledata.mso, too:
If dictAttachments.Exists("oledata.mso") Then dictAttachments.Remove("oledata.mso")
Now the dictionary ONLY contains the "Bar Attachment(s)"
Is there any way of establishing the connections BA<->AT, similarly as in questions #3 and #4 for IA<->AT?
I don't think there is any connection that you could possibly make. They are separate items and treated separately. Even when they are the same file, there's just no information in the InlineShape which would be useful for attempting to do this.
Email in HTML Format
All of the above is for HTML format emails. In the case of HTML mail, the problem is not so much in the Attachments but rather a limitation of the InlineShapes and InlineShape objects in that context.
Email in RTF Format
In the case of RTF mailbody, rather than being split png/wmz files, the attchment does appear by name in the Attachments collection, the other item 2 is actually a JPG as part of my signature.
HOWEVER, you will be able to observe that attachments in RTF have an OLEFormat property which and more specifically they have an OLEFormat.ClassType = "Outlook.FileAttach"
So you may be able to do something simple, like:
Select case m.BodyFormat
Case olFormatRichText
For each shp in doc.InlineShapes
If Not shp.OleFormat Is Nothing Then
If shp.OLEFormat.ClassType = "Outlook.FileAttach" Then
'Do something here
End If
End If
Next
Case olFormatHTML
' Do something like the example above for HTML
Case olFormatPlainText
' Do something different, if needed, for plain text emails
Case olFormatUnspecified
' not sure what to do here and it's not really my problem to figure out...
End Select
Now, given it as part of InlineShapes, I don't think you can "connect" it to a specific item in the Attachments collection. You will be better suited to simply iterate the Attachments collection.
Note: In my example (a very simple one) the two dictionaries/collections appear to be indexed the same way, but I would caution against assuming this will always be the case. So while you may be able to delete by index position, I am not sure that is a safe/reliable assumption.
It should not be possible in RTF format to have an empty Attachments collection and an "Inline Attachment".
There appears to be a large number of possible cases, depending on the combination of the following Enums (and perhaps some others):
MailItem.BodyFormat.
An OlBodyFormat, for the body text.
Possible values:
olFormatHTML,
olFormatPlain,
olFormatRichText,
olFormatUnspecified
InlineShape.Type.
An WdInlineShapeType, for each shape.
Possible values:
wdInlineShapeChart,
wdInlineShapeDiagram,
wdInlineShapeEmbeddedOLEObject,
wdInlineShapeHorizontalLine,
wdInlineShapeLinkedOLEObject,
wdInlineShapeLinkedPicture,
wdInlineShapeLinkedPictureHorizontalLine,
wdInlineShapeLockedCanvas,
wdInlineShapeOLEControlObject,
wdInlineShapeOWSAnchor,
wdInlineShapePicture,
wdInlineShapePictureBullet,
wdInlineShapePictureHorizontalLine,
wdInlineShapeScriptAnchor
Attachment.Type.
An OlAttachmentType, for each attachment.
Possible values:
olByReference,
olByValue,
olEmbeddeditem,
olOLE
I have examined some of these cases. The information provided is based on this limited information.
Is there a comprehensive way to access IA?
I would say YES, with MailItem.Inspector.WordEditor.InlineShapes (IA).
Depending on the personal definition of "attachment", there might be some items in this collection that are not regarded as such. The access is comprehensive though: there may be more items than looked for, but none is left out.
Is there a comprehensive way to access BA?
I would say YES, with MailItem.Attachments (AT).
I found an explanation for emails with nonempty IA and empty AT.
They have InlineShapes of type wdInlineShapeLinkedPicture. But even in this case, there are at least two possibilities, according to InlineShape.Hyperlink:
1) There is no Hyperlink.
This is the case when images are embedded, adding one item to IA per InlineShape, and at least one item to AT (there may be many InlineShapes, linked to a single Attachment).
In this case, properties of LinkFormat reveal useful info, including the name of the item in AT related the item in IA.
2) There is an Hyperlink (case partly the culprit for the different findings).
This is the case when images are hyperlinked and not embedded. Images show up in the email, adding one item to IA per InlineShape, but they do not add items to AT.
In this case, properties of Hyperlink and LinkFormat reveal useful info.
Case 1 appears to be the standard way of attaching images (up to Office 2013?). Using case 2 appears to require some tweaking (see this, this, this, and this).
Having a reference to an item in IA, is there any way of knowing if there is a corresponding item in AT (there may be not, according to #2), and if so identify it, IA->AT?
YES, at least in some cases.
When InlineShape.Type=wdInlineShapeLinkedPicture, if there is no InlineShape.Hyperlink then there is an item in AT. It can be found by pairing InlineShape.LinkFormat.SourceName (up to character #) with some Attachment.DisplayName.
On the other hand, I could not do this when InlineShape.Type=wdInlineShapeEmbeddedOLEObject (e.g., an inline attached Excel workbook).
I will edit with additional findings.
PS1: http://www.msoutlook.info/ has very useful info.
E.g.,
http://www.msoutlook.info/question/126,
http://www.msoutlook.info/question/205,
http://www.msoutlook.info/question/21,
http://www.msoutlook.info/question/261.
PS2: perhaps using some developers interface provides some access beyond VBA. I.e., some YESes to teh questions, which for VBA are NOs.
See
http://msdn.microsoft.com/en-us/library/microsoft.office.interop.word.inlineshape.hyperlink%28v=office.14%29.aspx
and
http://msdn.microsoft.com/es-es/microsoft.office.interop.outlook.attachment_members.
The first picture is for an email in the RTF format. The attachment icons are rendered inside the message body. The second screenshot is for a plain or HTNML message. In both cases the attachments can be accessed through the MailItem.Attachments collection.