Problem: Handle the incoming emails using vbscript.
Outlook Version: Outlook 2000
Description: I cannot use VBA for this as I believe Outlook 2000 doesn't let you run a VBA script from the rules wizard and hence I have to use the Run a Program | VBScript method.
What I know: I know how to handle email from VBA like this
Sub Sample(MyMail As MailItem)
Dim strID As String, olNS As Outlook.NameSpace
Dim olMail As Outlook.MailItem
strID = MyMail.EntryID
Set olNS = Application.GetNamespace("MAPI")
Set olMail = olNS.GetItemFromID(strID)
'~~> Rest of the code
Set olMail = Nothing
Set olNS = Nothing
End Sub
I also know how to run the vbscript on the email which is already in the inbox. To run a vbscript in OL2000, you have to use Run A Program and point it to the vbs file. The Run A Script is not available in OL2000.
What I do not know: And this is where I need help. How to get the mail object which has not hit the mail inbox in VBS. Once I get the object then I can do the rest of the necessary operations.
You are correct that OL2000 cannot run a VBA macro from a rule, if this article is to be believed.
Here's how I handle incoming emails. It does use VBA but as far as I know, there isn't a way to do so in VBScript.
Private WithEvents Items As Outlook.Items
Private Sub Application_Startup()
Dim olApp As Outlook.Application
Dim objNS As Outlook.NameSpace
Set olApp = Outlook.Application
Set objNS = olApp.GetNamespace("MAPI")
Set Items = objNS.GetDefaultFolder(olFolderInbox).Items
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
'~~> do something with the new message here
End If
ProgramExit:
Exit Sub
ErrorHandler:
MsgBox Err.Number & " - " & Err.Description
Resume ProgramExit
End Sub
This code should be pasted into the ThisOutlookSession module, then Outlook should be restarted.
Related
I am trying to run a VBScript that searches all the Incoming messages for a specific string on the subject field and replaces it with something else but keeping the rest of the subject content. So far, this is my code but im not getting any results.
Incoming mails subject: [EXTERNAL] abcdfed ghijk lmno
What i need: [*] abcdfed ghijk lmno
Sub RunAScriptRuleRoutine(MyMail As MailItem)
Dim strID As String
Dim olNS As Outlook.NameSpace
Dim msg As Outlook.MailItem
Dim rply As Outlook.MailItem
strID = MyMail.EntryID
Set olNS = Application.GetNamespace("MAPI")
Set msg = olNS.GetItemFromID(strID)
' do stuff with msg, e.g.
msg.Subject = Replace(msg.Subject, "[EXTERNAL]", "[*]")
msg.Save
Set msg = Nothing
Set olNS = Nothing
End Sub
I will appreciate your help
Changes to the subject for received messages will only be reflected in the header UI. You also have to change the MailItem.ConversationTopic value, but it is read-only. However, you can use PropertyAccessor.SetProperty("http://schemas.microsoft.com/mapi/proptag/0x0070001F", "New subject") to update it.
Whenever I hit an error with my script, the focus turns to the VBA code and the offending line. I fix it, and hit save. Then I notice that the script is no longer running, even after I make sure that it's not paused.
For example, right now I'm using a Form_Timer() event to do some testing (interval set to 1000ms). To test the script again, I just set it to a minute in the future (e.g. if the current time is 8:54:00 AM I set it to fire at 8:55:00 AM). But this stops working after an error. Does anyone know why this is? I don't want to have to tell my users to close and re-open their copies of the Access DB just to make the script work again.
Code:
Private Sub Form_Timer()
On Error GoTo ErrorHandler
current_date_time = Now
If current_date_time = #6/28/2016 8:52:00 AM# Then
MsgBox ("the current_date_time variable holds: " & current_date_time)
'Declare objects
Dim dbs As DAO.Database
Dim rst As DAO.Recordset
Dim qdf As DAO.QueryDef
Dim oApp As Outlook.Application
Dim oMail As Outlook.MailItem
Dim mail_body As String
'Set objects
Set dbs = CurrentDb
Set qdf = dbs.QueryDefs("qry_BMBFLoc")
Set rst = qdf.OpenRecordset
Set oApp = New Outlook.Application
Set oMail = oApp.CreateItem(olMailItem)
mail_body = "The following jobs do not have the special BF location set in Job Orders: " & vbCrLf
If Not (rst.EOF And rst.BOF) Then
rst.MoveFirst
Do Until rst.EOF = True
mail_body = mail_body & rst!job & "-" & rst!suffix & vbCrLf
rst.MoveNext
Loop
'Email contents
oMail.Body = mail_body
oMail.Subject = "Blah"
oMail.To = "someone#something.com"
oMail.Send
'Close stuff
rst.Close
dbs.Close
Set rst = Nothing
Set oMail = Nothing
Set oApp = Nothing
End If
End If
Exit Sub
ErrorHandler:
Dim msg As String
If Err.Number <> 0 Then
msg = "email Form Timer Error #" & Str(Err.Number) & " error Line: " & Erl & Chr(13) & Err.Description
MsgBox msg, , "Error", Err.HelpFile, Err.HelpContext
End If
Exit Sub
End Sub
In order to reactivate the code, you could close the form when the error is triggered. The user would then have to reload the form to complete the action.
However, without any intervention the error is likely to occur again.
Edit: Or you could write a Function to automatically close, and re-open the offending form. Calling it in the on error command.
When there is an error in access form, the timer will stop working, you don't need to close and reopen the whole database, only the form to start the timer again. Otherwise you can add a button called "refresh" and bind macro to it which will turn the timer on again.
Yeah this sucks. I am writing a vba script for outlook and so the only way to debug is to close and reopen outlook after every error.
Here is the code I have so far:
Option Explicit
Call OpenOutlook()
Function OpenOutlook()
Dim ObjShell
Set ObjShell = CreateObject("WScript.Shell")
ObjShell.Run("Outlook.exe")
Call SendEmail()
'I tried closing from here but this didn't work either
'ObjShell.Quit
End Function
Function SendEmail()
'Declaring variables used through out this function
Dim ObjOutlook
Dim objMail
Set ObjOutlook = CreateObject("Outlook.Application")
'CreateItem(0) opens a New Email window...MailItem
set objMail = ObjOutlook.CreateItem(0)
objMail.Display
'MailItem Options
objMail.to = "test#mail.com.com"
'objMail.cc = "test2#mail.com"
objMail.Subject = "Did it work!?"
objMail.Body = "If you got this email, my VBs test worked!"
'objMail.Attachments.Add("C:\Attachment\abc.jpg")
objMail.Send
'This didn't work either
'If objMail.Sent = True Then
'ObjOutlook.Quit
'End If
'Quit closes Outlook like I want but it doesn't wait for the email to send
'ObjOutlook.Quit
End Function
What I'm trying to automate using VBScript:
Open Outlook
Send an email
Wait for email to send (Outbox to finish sending)
Close Outlook AFTER the email has been sent
Where I'm stuck:
First of all, I was having trouble opening Outlook. Below is the code that I used to create an Outlook Object:
Set ObjOutlook = CreateObject("Outlook.Application")
'CreateItem(0) opens a New Email window...MailItem
set objMail = ObjOutlook.CreateItem(0)
objMail.Display
What I did (Not even sure if this is the right way to do it):
Set ObjShell = CreateObject("WScript.Shell")
ObjShell.Run("Outlook.exe")
Why can't I just do ObjShell.Quit after I call the SendEmail() Function? Using .Quit gives me an error.
I just want to close the Outlook application once the email has been sent and I can't figure out how.
MailItem has a Sent property that indicates when the message has been sent. Try this:
...
objMail.Send
Do Until objMail.Sent
WScript.Sleep 500
Loop
' Safe to close...
ObjOutlook.Quit
Try this:
Option Explicit
Sub SendMail()
Dim outobj, mailobj
Set outobj = CreateObject("Outlook.Application")
Set mailobj = outobj.CreateItem(0)
With mailobj
.To = "user#test.com"
.Subject = "Testmail"
.Body = "If you got this email, my VBs test worked!"
.Send
End With
'Clear the memory
Set outobj = Nothing
Set mailobj = Nothing
End Sub
SendMail()
Msgbox("Done")
Firstly, what if it was the user who opened Outlook? I don't think any user will appreciate your code closing Outlook. You might want to check that both Application.Explorers.Count and Application.Inspectors.Count are zero before closing Outlook. Newest version of Outlook will automatically exist if there are no open explorers or inspectors even if you hold a reference to an Outlook object - that was done to guard ageist misbehaving apps that leaked references. To prevent Outlook from closing, hodl a reference to an Explorer object t(even if you do not show it) - call Namespace.getDefaultFolder(olFolderInbox), then hold a reference to the object returned by MAPIFolder.GetExplorer .
Secondly, after calling Send, use Namespace,SyncObjects collection to retrieve the very first SyncObject. Hook up the SyncObject.SyncEnd event and call SyncObject.Start. When SyncEnd event fires, you will be all done. But I don't think you can work with events in VB script...
I have rules set up to copy emails containing certain keywords to specific folders and mark as read.
The problem i'm having is when it copies those emails to the folders it marks the original email in the inbox as read, and which can cause me to miss the message.
If i don't mark it as read then when i read it in the Inbox it stays unread in the specific folder.
I cant find any rule properties to accomplish this, anyone have any ideas?
Set the rules to copy to the target folders but not mark as read.
Put this untested code in the ThisOutlookSession module. Assumes the target folders are directly under the Inbox. If buried deeper, add .Folders as necessary.
Option Explicit
' one line for each target folder
Private WithEvents myOlItemsA As Outlook.Items
Private WithEvents myOlItemsB As Outlook.Items
Private Sub Application_Startup()
Dim olApp As Outlook.Application
Dim objNS As Outlook.NameSpace
Set olApp = Outlook.Application
Set objNS = olApp.GetNamespace("MAPI")
' one line for each target folder
Set myOlItemsA = objNS.GetDefaultFolder(olFolderInbox).Folders("targetfoldernameA").Items
Set myOlItemsB = objNS.GetDefaultFolder(olFolderInbox).Folders("targetfoldernameB").Items
End Sub
' one copy of ItemAdd code for each target folder
Private Sub myOlItemsA_ItemAdd(ByVal item As Object)
On Error GoTo ErrorHandler
Dim Msg As Outlook.MailItem
If TypeName(item) = "MailItem" Then
Set Msg = item
Msg.Unread = False
End If
ProgramExit:
Set Msg = Nothing
Exit Sub
ErrorHandler:
MsgBox Err.Number & " - " & Err.Description
Resume ProgramExit
End Sub
Private Sub myOlItemsB_ItemAdd(ByVal item As Object)
' same code as for myOlItemsA
End Sub
Code based on this post Using VBA to read new Outlook Email?
The rules move mail to target folders. The ItemAdd code acts on the items added to the target folders.
In Visual studio 2010>New Project>Visual Basic>Windows>Windows forms Application, i have made a form (form1.vb) and a database (Local Database>"Database1.sdf") and a Table with 3 Columns ("Name","City","Age").
I like to copy this 3 fields and paste to document "test1.doc" (open this with Ms Office or Open Office Writer). I have bookmarks ("PasteName", PasteCity", "PasteAge") in specified places in test1.doc .
How to make a button to open the document "test1.doc" and copy - paste this 3 items from table to doc and preview before print it? (not for save - only print preview and close without save after printing)
I have find this code for MS Office but didn't work in Visual Studio. I like something similar. (this code is for a doc Form Fields - I have Bookmarks in my doc).
Private Sub cmdPrint_Click()
Dim appWord As Word.Application
Dim doc As Word.Document
Set appWord = GetObject(, "Word.Application")
Set appWord = New Word.Application
Set doc = appWord.Documents.Open("C:\WordForms\CustomerSlip.doc", , True)
With doc
.FormFields("fldCustomerID").Result = Me!CustomerID
.FormFields("fldCompanyName").Result = Me!CompanyName
.FormFields("fldContactName").Result = Me!ContactName
.Visible = True
.Activate
End With
Set doc = Nothing
Set appWord = Nothing
End Sub
Thanks programers people
This works for me. (button action)
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
'Print customer slip for current customer.
Dim appWord As Word.Application
Dim doc As Word.Document
'Avoid error 429, when Word isn't open.
On Error Resume Next
Err.Clear()
'Set appWord object variable to running instance of Word.
appWord = GetObject(, "Word.Application")
If Err.Number <> 0 Then
'If Word isn't open, create a new instance of Word.
appWord = New Word.Application
End If
doc = appWord.Documents.Open("D:\Test.docx", , True)
doc.Visible()
doc.Activate()
With doc.Bookmarks
.Item("Name").Range.Text = Me.NameID.Text
.Item("City").Range.Text = Me.CityID.Text
End With
Dim dlg As Word.Dialog
dlg = appWord.Dialogs.Item(Word.WdWordDialog.wdDialogFilePrint)
dlg.Display()
'doc.Printout
doc = Nothing
appWord = Nothing
Exit Sub
errHandler:
MsgBox(Err.Number & ": " & Err.Description)
End Sub