I am using VBA to format all outbound email messages in a certain way before sending. For example, I want to remove the first column from all tables which are embedded in the email. I use the following code:
Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)
Dim wd As Word.Document
Set wd = ActiveInspector.WordEditor
Dim tb As Word.Table
For Each tb In wd.Tables
tb.Columns(1).Delete
Next tb
End Sub
The above code works perfectly. However, the problem is that I only want to format my email text. Often, I will be responding to or forwarding someone else's email, which means that the text of the previous email will be in the same Inspector window. I don't want to format the text/images/etc. of the previous emails in the thread. How can this be achieved?
I know that each email within a thread--although they're all in the same window--is an individual unit. I know this because when reading an email which is part of a thread, as you move the mouse, you will see
on the right side of the screen, indicating where the next part of the thread is. When composing a new email (reply or forward) which is part of the thread, the above buttons are not shown, but you will still see a blue horizontal line separating the different parts of the thread from each other.
I was thinking that maybe I can search for the first occurrence of the line in the email, and only apply the formatting up until that point. However, it appears that the line isn't really text or any regular formatting which is searchable in the normal sense. In fact, if you copy the email text (before sending), and then paste into Word, the line disappears.
Any suggestions?
Thanks!
Update
My question has nothing to do with the "conversation view" found in versions 2010 and later.
Outlook 2010 allows you to view the other emails in the thread in one group. What I want, however, is to be able to loop through (via code) the emails in the thread within the same email. So, if there was an email "a", and then a reply, "b", and then another reply, "c", c will also contain b beneath it, and then a beneath that, all within the same email. In pseudo-code, I would want the following:
Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)
Dim wd As Word.Document
Dim smail as SubEmail
Dim tb As Word.Table
Set wd = ActiveInspector.WordEditor
For Each smail in wd
For Each tb In wd.Tables
tb.Columns(1).Delete
Next tb
Exit For
Next smail
End Sub
Update
I found a similar feature in Exchange Web Services, called UniqueBody. See here. That's exactly what I'm looking for, just not with Exchange.
Why not just look for "From:" chr(13) "Sent:" ? Outlook is going to put those tags in any email regardless of where it came from.
Assume that the entire body of emails a, b, c in your example above are in sBody:
Sub GetFirstThread()
Dim olItem As Outlook.MailItem
Dim sText As String
Set olItem = ActiveExplorer.Selection.Item(1)
sBody = olItem.Body
i=1
While i < Len(sBody)
If Asc(Mid(sBody, i, 1)) = 13 Then 'Look for From:
If Mid(sBody, i + 1, 5) = "From:" Then
'we found the start of email b
nPosEb = i
End If
End If
i=i+1
Wend
'...do something with nPosEb
End Sub
Related
I'm trying to create a userform that will add text to the Word document based on a mixture of inputs coming from the userform. It could be checkboxes, lists, or textboxes where one writes content. As I was looking around for codes to preserve the bookmarks that I use to transfer the inputs into Word text, I came across one that allowed me to successfully preserve the bookmark for future editing. I thought I could use the same method for multiple bookmarks, but it seems not to work. With an example, now.
I have TextBox1, TextBox2 (in the userform), Bookmark1, Bookmark2 (in the Word document), and CommandButton1 to give the ok to transfer info from the userform to the Word document. I want to make TextBox1's content appear where Bookmark1 is, and TextBox2's content where Bookmark2 is. Code I tried is:
Private Sub CommandButton1_Click()
Dim BMRange01 As Range
Set BMRange01 = ActiveDocument.Bookmarks("Bookmark1").Range
BMRange01.Text = Me.TextBox1.Value
ActiveDocument.Bookmarks.Add "Bookmark1", BMRange01
Dim BMRange02 As Range
Set BMRange02 = ActiveDocument.Bookmarks("Bookmark2").Range
BMRange02.Text = Me.TextBox2.Value
ActiveDocument.Bookmarks.Add "Bookmark2", BMRange02
End Sub
When I tried with a single bookmark (from the first "Dim" to the last BMRange01) it worked just fine, and I could edit and re-use the bookmark multiple times. When I try with two of them, however, only one of them is preserved (or rather, deleted and created back again). Specifically, the second one seems to be preserved, while the first one (Bookmark1) is deleted.
Make your life a bit easier and create a separate sub to handle the work. Eg:
Private Sub CommandButton1_Click()
ReplaceBookmarkText ActiveDocument, "Boomark1", me.TextBox1.Value
ReplaceBookmarkText ActiveDocument, "Boomark2", me.TextBox2.Value
End Sub
Sub ReplaceBookMarkText(doc As Document, bmName As String, txt)
Dim rng As Range
Set rng = doc.Bookmarks(bmName).Range
rng.Text = txt
doc.Bookmarks.Add bmName, rng
End Sub
My task: I have multiple forms in one Word document and it has to be filled out with the same information such as company name, address, tax number, etc.
My experience with VBA is very limited so I used bookmarks and wrote some code:
Private Sub OKbutton_Click()
Dim FirmaName As Range
Set FirmaName = ActiveDocument.Bookmarks("FirmaName").Range
FirmaName.Text = Me.TextBox1.Value
Dim FirmaNameRio As Range
Set FirmaNameRio = ActiveDocument.Bookmarks("FirmaNameRio").Range
FirmaNameRio.Text = Me.TextBox1.Value
Me.Repaint
stinfo.Hide
The issue or challenge for me is, that I want to be able to "dynamically" change the data in the pop-up form. Now it works the way every time I press OK-button, it adds new data behind the previous, which is undesirable. If I make a mistake I want to change it only in the pop-up window, not in the document.
So is there any way to program it that the information typed in the pop-up window can rewrite the previous information?
It´s not necessary to use bookmarks or whatsoever. It just has to work, that it´s easy for other employees to fill out these forms and save some time by skipping mechanical copy-pasting.
Use code like:
Sub UpdateBookmark(StrBkMk As String, StrTxt As String)
Dim BkMkRng As Range
With ActiveDocument
If .Bookmarks.Exists(StrBkMk) Then
Set BkMkRng = .Bookmarks(StrBkMk).Range
BkMkRng.Text = StrTxt
.Bookmarks.Add StrBkMk, BkMkRng
End If
End With
Set BkMkRng = Nothing
End Sub
which you would call with code like:
Call UpdateBookmark "FirmaName" Me.TextBox1.Value
And, since you're using bookmarks, instead of writing the same value multiple times to different bookmarks, simply insert a cross-reference to the first bookmark whose value is to be repeated and, when you've updated all the bookmarks, use a single code line to update all the cross-references:
ActiveDocument.Fields.Update
I have designed an Outlook email form that holds several custom fields. One is "reference number", a free text box with the name "TextBox1":
I am trying to display the contents of that text box so I can later populate Excel, using this as a first step just to display the contents (doesn't work)...
MsgBox (msg.UserProperties.Find("TextBox1", Outlook.OlUserPropertyType.olText).Value)
Can anyone correct this line for me please? I want the message box to display "1234567".
Once I get that right, I can then copy the value into the Excel sheet.
Many thanks for your time.
Shane
(Wetherby, UK).
EDIT:
Here is more complete code showing the declaration and assignment of objects:
Dim rng As Excel.Range
Dim msg As Outlook.MailItem
Dim nmspace As Outlook.NameSpace
Dim folder As Outlook.MAPIFolder
Dim item As Object
Set nmspace = Application.GetNamespace("MAPI")
Set folder = nmspace.PickFolder
'Look at each email message in a folder
For Each item In folder.Items
intColumnCounter = 1
Set msg = item
intRowCounter = intRowCounter + 1
Set rng = wks.Cells(intRowCounter, intColumnCounter)
rng.Value = msg.To
...more items here to pick up sender address, subject, date sent, etc)...
MsgBox (msg.UserProperties.Find("TextBox1", Outlook.OlUserPropertyType.olText).Value)
'This is the field whose value I want to take for Excel
Next item
SECOND EDIT:
Here is a screen grab of the object's advanced properties:
It is a "normal" free text box entered into an email template. It's got the right name (TextBox1), and even has the right value (1234567). But somehow I cannot get the code to read the value of 1234567 and display it in the message box.
I'm stumped. it needs someone clever than me! Thank you to all who are pondering this one.
SOLVED!!! (Apologies for shouting).
Earlier replies got me thinking. I tried this line instead:
MsgBox (msg.UserProperties.Find("New - Study Number").Value)
as "New-Study Number" is what was used for the field name:
I think part of my problem was I was getting confused with the various usages (property name, field name, control name) and the VBA field properties boxes being a little unclear.
Nevertheless - thank you to all who contributed; I hope this helps others! 8)
So firstly, I'm very new to VBA and due to the number of emails I get that follow a certain template, I'm trying to automate the data collation to save myself from all the cutting and pasting that is currently required. I've looked at some previous questions but due to my very little knowledge, the answers aren't specific enough for me to understand.
Each one of these emails is from a particular email address and has a standard format as shown below:
"
dd/mm/yyyy hr.min.sec
xxx xxxxxxx xxxxxxxxxxxxxxxxx xxxx xxxxx "
I would like to export or copy this information to an excel 2003 worksheet so that each separate piece of information is in a new column of a single row, where each email is a new row.
I would like the macro to be able to search through my received emails in a particular folder (as I've already set up some rules in outlook relating to this email address), copy the information from each email matching the template and paste it into a single excel worksheet. Then each time I get a new email, the information will be added to the bottom of the table thats been created.
Hopefully that all makes sense, please let me know if you need anymore information.
Thanks in advance.
I did something exactly like this recently, except that I had it entered into an access database instead of an excel sheet, but the idea is the same. For some reason, I was having trouble getting it to run with rules, but I anyways found that I could control it better from a manually run macro. So use a rule to put everything into a folder, and make an AlreadyProcessed subfolder under that. Here is some code to start from:
Sub process()
Dim i As Integer, folder As Object, item As Object
With Application.GetNamespace("MAPI").GetDefaultFolder(olFolderInbox).Folders("YourFolderName")
For Each item In .Items
processMail item
item.Move .Folders("AlreadyProcessed")
Next
End With
End Sub
Sub processMail(item As Outlook.MailItem)
Dim bitsOfInformation() As String
bitsOfInformation = Split(item.Body, " ")
'Use this information to make an Excel file
End Sub
Making Excel files from VBA are very easy - just read up on opening excel and making new documents from other Office program VBAs - you're looking for Excel.Application. You can even record a macro in Excel, filling the information manually, and basically copy the code into Outlook and replace the hard-coded information with variables. But if you're going to be running this on thousands of e-mails, be warned that recorded macros (that use selection objects) are inefficient.
Start with the following code:
Private WithEvents Items As Outlook.Items
Private Sub Application_Startup()
Set Items = GetItems(GetNS(GetOutlookApp), olFolderInbox)
End Sub
Private Sub Items_ItemAdd(ByVal item As Object)
On Error GoTo ErrorHandler
Dim msg As Outlook.MailItem
If TypeName(item) = "MailItem" Then
Set msg = item
End If
ProgramExit:
Exit Sub
ErrorHandler:
MsgBox Err.Number & " - " & Err.Description
Resume ProgramExit
End Sub
Function GetItems(olNS As Outlook.NameSpace, folder As OlDefaultFolders) As Outlook.Items
Set GetItems = olNS.GetDefaultFolder(folder).Items
End Function
Function GetNS(ByRef app As Outlook.Application) As Outlook.NameSpace
Set GetNS = app.GetNamespace("MAPI")
End Function
Function GetOutlookApp() As Outlook.Application
Set GetOutlookApp = Outlook.Application
End Function
This sets an event listener on your default Inbox. Whenever an email message is received, the code inside the If TypeName statement will be executed. Now it's simply a matter of what code you want to run.
You can check the sender using the .SenderName or .SenderEmailAddress properties to make sure it's the right sender.
If you provide more specific information, I can amend the code.
I use Outlook (MS Exchange) and have an individual as well as two group inboxes (I'm working logged in with the individual profile through which I also have access to the group inboxes).
When I send an email, I chose either my individual or one of the two group email addresses in the From field. When the email is sent, I want a copy saved in the inbox of myIndividualMailbox, groupAMailbox, or groupBMailbox depending on which From email address I used.
Example: If I send an email From groupA#myCompany.com, I want a copy of the email saved in the inbox of the groupAMailbox (and not in my individual inbox).
I have understood that this is not possible by setting up a rule in Outlook but that it could be done with a VBA macro. I don't now how to write the VBA macro and don't know if this is a just a short script or more complicated. In fact I have never written a macro in Outlook so I don't even know how to begin. Can anyone show how to do this?
I started looking for a solution with this question: Outlook send-rule that filter on the 'From' field
I made this for you as far as I can tell, it works. You should put this in the Microsoft Outlook Objects - ThisOutlookSession Module.
Note that the myolApp_ItemSend event will never trigger unless you run enableEvents first. And you will need to make sure it is enabled every time you close an re-open Outlook. This will take some customization, but it should give you the general idea.
Option Explicit
Public WithEvents myolApp As Outlook.Application
Sub enableEvents()
Set myolApp = Outlook.Application
End Sub
Private Sub myolApp_ItemSend(ByVal item As Object, Cancel As Boolean)
Dim items As MailItem
Dim copyFolder As Outlook.Folder
Dim sentWith As String
'Identify sender address
If item.Sender Is Nothing Then
sentWith = item.SendUsingAccount.SmtpAddress
Else
sentWith = item.Sender.Address
End If
'Determin copy folder based on sendAddress
Select Case sentWith
Case "groupA#myCompany.com"
'get groupAMailbox's inbox
Set copyFolder = Application.GetNamespace("MAPI").folders("groupAMailbox").folders("Inbox")
Case "myE-mailAddress"
'get My inbox
Set copyFolder = Application.GetNamespace("MAPI").folders("myE-mailAddress").folders("Inbox")
End Select
'copy the Item
Dim copy As Object
Set copy = item.copy
'move copy to folder
copy.Move copyFolder
End Sub
EDIT: It looks like they've actually built the event functionality into the Application object for Outlook directly now, but it from testing you still have to do what I outlined above.
Outlook stores all sent items in default sent items folders. however you can apply a patch to save sent items in its own folder.
http://support.microsoft.com/kb/2181579