Can VBA code run after an application is closed? - vba

I am using the ItemAdd event to watch for new Outlook emails. Does this event work while the application is closed?
Currently, my macro launches upon initial startup using the "Application_Startup()" event, and then initializes a class module containing a sub routine that is trigged with the "ItemAdd" event. If I close Outlook, will this macro still be watching for a new "ItemAdd" event?
Thanks!

No, it will not - the event is fired by the application only, so no application - no event.
Keep in mind that if this is a cached profile, these events will fire on application startup when the cached mailbox (OST) is updated. You can also work around this by processing all unread emails on startup (assuming they stay unread). Or you can persist the MailItem.ReceivedTime property of your last processed message and process all emails newer than that on startup.

Related

WithEvents object in Outlook VBA eventually fails to raise event

Okay, looks like someone has encountered this problem before, but I didn't see any further comments or solutions. See the Edit in the accepted answer to this question.
My situation is like this.
I am running Outlook 2013 under Win10 x64 with an Exchange email account. I sometimes run Outlook for several days to a week or more at a time without closing it.
I want to raise an event when a new item is added to the Sent Mail folder. This needs to occur after the Application ItemSend event because, let's say, I want to delete the message after it is sent, which you cannot do from within the ItemSend event handler.
So I have the following code:
Public WithEvents goSent As Outlook.Items
Private Sub Application_Startup()
'Establish the global object for the folder we want to monitor.
Set goSent = Session.GetDefaultFolder(olFolderSentMail).Items
End Sub
Private Sub goSent_ItemAdd(ByVal Item As Object)
'Do stuff here.
End Sub
Everything works beautifully for a day or longer, but eventually the ItemAdd event handler stops firing. If I enter the VBA editor and manually run Application_Startup, then it starts working again.
[Edit:] One other bit of information: The "built-in" events, like Application ItemSend, always seem to fire reliably no matter how long Outlook has been running.
[Edit 2:] This time, I let things go for a day after the event stopped firing. I opened the VBA editor and put a breakpoint in the Application ItemSend procedure. When it stopped, I queried the goSent object and found that (a) it still existed (rather than being Nothing), but (b) it had only the items in it that were there yesterday, presumably at the time it became "untethered" from the Sent Mail items collection. When I submitted a new Set statement in the Immediate window, it immediately began to work again.
[Edit 3:] I noticed that the MSDN documentation says to put event handlers for custom objects--like my ItemAdd event--in class modules. I have mine in ThisOutlookSession, but it was my understanding that ThisOutlookSession is a class module. Is there a problem with that?
Any idea why this would happen and what to do about it? I considered adding an event handler for Application ItemSend and just reassigning the goSent object every time that's fired, but it doesn't address the underlying problem.
[Edit 4:] For a while now, I've had a Set statement in the Application ItemSend handler, and that seems to have mostly taken care of things, even though it's a workaround, not really a solution. It appears to fail when I have delayed delivery on a sent item for an extended time, and I don't send any further messages in the meantime. Then the goSent object disconnects from the Sent Mail collection, and the message is actually sent from the Outbox after that point and before Application ItemSend fires again.
Thanks!
[Edit 5:] Unrelated to original issue: I discovered that my macros fail to accomplish what I want with an Exchange server that is in online mode (i.e., not cached mode) if I have messages in the Outbox with delayed delivery and Outlook is closed when the delivery time passes. In online mode, Exchange itself sends these messages and adds them to the Sent Mail folder on the server, so when Outlook reopens, the messages are already in the Sent Mail collection and no event fires. Which makes sense. See discussion here. Looks like I would need to add something to my Application_Startup macro to look for messages sent since Outlook last closed.
I had similar issue and never found a proper solution. What I did was I wrote a little batch script that closes and opens outlook app, then I set a task in task scheduler to run it every hour outside of my working hours. You can also do it easily in vbs.

How to capture the tick event of the task checkbox on 'Outlook Today'? VSTO Add-in

I'm developing an Outlook Add-in, and currently I have no idea on how to capture the task's checkbox (mark complete) tick event -- particularly on the 'Outlook Today' view. I'd like to override it with my own function.
Refer to the attached image as reference to the checkbox being referred to.
Outlook Today Task
The Outlook Today page is not a typical area that can be integrated with. It is possible though, as it is basically an .html page; see: https://technet.microsoft.com/library/cc750169.aspx. However, this is 20 year-old technology...
If you are mainly interested in trapping changes to that task, then you can trap the Items.ItemAdd event for the Tasks folder and do whatever you like with the modified Task.
The Outlook object model doesn't provide anything for the Outlook Today page. It just lists items from your folders. So, you may consider handling the following events to get the job done:
The ItemChange event of the Items class which is fired when an item in the specified collection is changed.
The PropertyChange event of Outlook items which is fired when an explicit built-in property of an object is changed.
Both events are fired when you mark the task as completed. But in case of the PropertyChange event you need to subscribe to each task item individually which is not really convenient.

How can the Add.Item event works at Outlook opening?

I got an issue with the macro I did in Outlook. To resume, the macro starts every time I receive an email. Then it will run a few others Sub, modify an Excel file and so one. When Outlook is running and I receive a new email, everything works perfectly. The problem occurs when I open Outlook and I receive more than one email at the same time.
I suppose the macro doesn't have enough time to end what it's doing with the first email and already try to start again with the next one.
Is there a way to keep the next emails in suspend in order to run the macro for each email, each one has its turn ? Or maybe you have another solution ?
Thank you.
PS: I can provide the code but it's very long.
The problem occurs when I open Outlook and I receive more than one email at the same time.
The NewMailEx event of the Application class is fired once for every received item that is processed by Microsoft Outlook. The item can be one of several different item types, for example, MailItem, MeetingItem, or SharingItem. The EntryIDsCollection string contains the Entry ID that corresponds to that item.
The NewMailEx event fires when a new message arrives in the Inbox and before client rule processing occurs. You can use the Entry ID returned in the EntryIDCollection array to call the NameSpace.GetItemFromID method and process the item.
Make sure VBA macros are enabled and allowed to run when Outlook is started. Check out the Trust Center settings in Outlook.

Event in outlook application object model to know when the first click happens on message body box?

I am developing a add-in to perform some actions when the first click happens on the message box in outlook (2013 version). I want to capture the Outlook.MailItem.Recipients as soon as the first click happens on message body box.
Possible approach to do this (just did a quick test, seems to work for 2013):
Register to NewInspector event of the Application object:
Application.Inspectors.NewInspector += ....;
In the event handler, register to the following event:
var editor = newInspector.WordEditor as Word.Document;
editor.Application.WindowSelectionChange += ....;
The handler fires when the selection changes, which is also happening when the user clicks the window.
Please note that you must keep references to all objects in this sample, else the event registrations will get lost.

Keep VB.NET application running in the background after base form closed

I am writing an application in VB.Net in which a user can schedule emails to be sent in the future. Is there a way to keep my listener thread running in the background after the base form on the application is closed? I would also need to start up the listener when the system boots, but wouldn't want any forms to open at that time.
Example (desired) functionality: I open the application in the morning and schedule three emails, one of which should be sent in three hours, and the other two of which should be sent tomorrow morning. I close the application. In three hours, the first one sends. At the end of the day, I shut down my machine. When I turn it back on tomorrow morning, the other two are sent without me ever opening the application.
I am thinking I need to separate the listener into a service, but want to make sure there isn't an easier way before going down that road.
If I do end up having a separate service and application, can I create an installer that will install both at once?
In the options of your project, set the “Startup Object” to “Sub Main” instead of of a form name. You might have to disable the setting “Application Framework” first.
Now you have to launch the form manually because it’s no longer done automatically, but on the other hand you can now control when to launch it, and your application will exit when it reaches the end of the Main method (or when it’s quit explicitly) rather than when the form closes.
If all you want is to keep the program running, you could supply it with the definition for a TaskBar icon, and represent state in your application using the icon's graphic. It would appear over on the right next to the system clock.
Then it's just a matter of reconfiguring your development project so that the application close event is triggered off that icon's menu instead of off the fact that the form is closed.
Use a NotifyIcon control and when the user close the mainform capture the OnClosing Event to Ask the Question if he want to minimize to the tray or exit the application.
Here is the documentation of NotifyIcon control from Microsoft:
NotifyIcon Control
I have a possible solution for you here. In the form closing event you can place the following code:
Private Sub Form1_FormClosing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
Me.Visible = False
e.Cancel = True
End Sub
This will hide the form and allow it to run in the background until you shutdown the computer. To handle the restart and then send emails I'd suggest adding the emails to be sent to a text file that can be accessed after restart and then adding the program to startup. An even better solution might be to have 2 programs, one that is on startup and is always hidden that checks the text file every 15 minutes (for example) and a second program that is launched when a new email is to be added to the list and it appends the text file with new emails to be sent.
(Sorry if i am wrong, just proposing a probable solution here)
I think attaching a simple db to hold the email sending schedule information/date-time and loading the application at startup with Notification Icon (or without Notification Icon but with a shortcut to show user interface/form to feed the emails and schedule information/date-time, if required + BackgroundWorker, if you want the application to go to sleep mode and wake it later to send first scheduled email; after X hours). After sending first email update the db then exit the application. Check the db on startup to send the first email or go to sleep mode if pc boots before sending first email. But, if first email is already sent then send other two scheduled emails (check db date-time). This should do the job...
:)