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

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)

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.

Turning a string of characters into a hyperlink

I have searched a ton for an answer to this question and I can't seem to find one that is specific to my needs. I think it might be possible that I am just not understanding how hyperlinks work in VBA.
Currently, I have an array of strings (each representing a separate file on my server), and I want to add a hyperlink to each string that will take it to the file location on my server. I want that string to be hyperlink-ed so when I paste it in to Word or Outlook, it will already be hyperlink-ed. In my mind, it seems like this should be a fairly straight-forward task; you have a string of text, you have a file location, and you want to hyperlink that string of text with the file location.
For example, let's say I have an array like below:
docArray = {"myDoc1", "myDoc2", "myDoc3"}
which contains the names as string of 3 documents.
I have another array with the file location of each doc:
docLocArray = {"C:\Documents\myDoc1.docx", "C:\Documents\myDoc2.docx",
"C:\Documents\myDoc3.docx"}
The pseudo-code for this would be something like:
Hyperlink.Add(docArray(1), docLocArray(2))
Is there any way I can do something like this, or am I completely misunderstanding how hyperlinks can be used?
I am working in Autodesk Inventor if that is of any relevance to anyone.
Try this in Word:
ActiveDocument.Hyperlinks.Add Anchor:=Selection.Range, Address:="C:\Testdir\Testfile.txt", SubAddress:="", ScreenTip:="", TextToDisplay:="MyFile"
Then just loop through the arrays for the values of Path and Filename.

Word / PDF - Merge Documents

I am looking to merge two documents, however it is not your typical merge.
My first document is a mailmerge, creating a cover letter, basically each page has a name and address
My next document is a static document that cannot be changed.
I need to insert the static document into my first merged document, but after every page, therefore, for every one page a document is inserted.
I have tried the insert document in both word 2010 and pdf using adobe acrobat, and as you have thought it only inserted one document after the first page.
I'm looking at VBA, but I have never utilized VBA and word before
Any pointers would be appreciated.
Many thanks
I should have spent more time on this.
The original template contains fields to merge.
On the static document that I mention, click insert tab, Text Section, select Object - Text From File
Select the cover letter / template that contains the fields to merge. This will insert the template followed by the static document that cannot be changed
Note I have spotted some formatting changes on the template following merge - further work required
From this point start your mail merge, and complete merge to Adobe or word.
This creates a mail merged document containing the cover letter with name and address fields followed by the static document.
Extremely simple. I always over complicate things!
I'll work on the changed formatting, but other then that this works

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.

VB, Outlook Macro: How to put variable, (fields), in an email template

I have a simple macro that reads Strings from a .csv file. I want to place (Replace) those Strings into the body of an email. The email will be opened from a template, so I want the fields in the template, and then have my macro start a new email from the template and replace the fields with the String variables.
I'm not finding anything posted that shows how to format such a field in the body of the email.
A link to a reference would be helpful.
The rest of the story: The email template body was pasted from a Word mailmerge document, so it already has mailmerge fields in the correct locations. There is probably a way to make mailmerge work in Outlook, but mailmerge in Word was problematic, and I don't know what makes mailmerge tick, so when it broke on a user's computer I had to rebuild the merge document, etc. Now we're switching to email instead of a printed Word document, and I'm more comfortable with writing a macro to explicitly place the data. I haven't done much programming in vba, so I'm picking up the syntax piece by piece as I go.
There are no fields. Your Outlook .oft template should contain unique string placeholders.
Once you .CreateItemFromTemplate, replace the unique string placeholders.
MyMail.HTMLBody = Replace(MyMail.HTMLBody, "UniqueStringPlaceholder_1", "csvstring_1")
You will likely work out some kind of loop.