Setting Default Signature selection in Outlook - vba

I can't find an answer to this on the forum, or maybe i'm not typing my query in accurately enough.
With my Outlook 2010 at my workplace the default Signature block keeps getting changed to a default option when I load up Outlook. I don't have access to the source file to make any changes as it is all Server side.
What I want to do is change the default selection of my Signature from the old one to a new one.
Under File -> Options -> Mail -> Signatures I want to change my default Signature to something else upon start up of Outlook 2010 using a VBA code of some form. Is there any way that this can be done?
I have already created the new Signature but I need to reselect it as the default option every time I log onto my terminal, which is frustrating.
Looking for any help please.

After some cursory searching, it looks like Outlook signatures are managed through the Windows registry (for example, see here and here). Specific registry paths seem to depend on your version of Outlook.
Of course, if it's your work email, it's likely you can't make any changes to your registry.
However, if all you want is to automatically insert some specific text to any new email, that can be done via VBA. Basically, you want to use the Open event of a new email to insert specific text. To do that, you need to add the Open hook during the ItemLoad event. Something like this:
' declare the mail item that will have the Open event available
Public WithEvents myItem As Outlook.mailItem
' defines how the Open event will be handled
' note that you only want to do this with unsent items
' (hence the .Sent check)
Private Sub myItem_Open(cancel As Boolean)
If Not myItem.Sent Then
'insert your signature text here
End If
End Sub
' hooks the Open event to a mail item using the ItemLoad event
Private Sub Application_ItemLoad(ByVal Item As Object)
Dim mailItem As Outlook.mailItem
If Item.Class = OlObjectClass.olMail Then
Set myItem = Item
End If
End Sub
For more information, see the relevant Microsoft articles on the Application.ItemLoad event and MailItem.Open event.

Related

Make a copy of the printed Word document and save it in a folder

I need a to create a macro on my Word which would save the printed document automatically to another location on my computer. I have looked through hundreds of options online and here also but couldn't exactly what I was looking for. Saving it to another location is easy but it should make a copy only when the the document is in the print queue. Can anyone help me out here? Need it for my employee monitoring.
Use the Application.DocumentBeforePrint event which is triggered everytime before the opened document is printed.
The following code needs to be placed in a class module, and an instance of the class must be correctly initialized.
Option Explicit
Public WithEvents App as Word.Application
Private Sub App_DocumentBeforePrint(ByVal Doc As Document, ByRef Cancel As Boolean)
Doc.SaveAs2 FileName:="your path"
End Sub
Code 1: Put this code into a class module called "EventClassModule".
According to Using events with the Application object you need to register the event handler before it will work.
Option Explicit
Dim ThisWordApp As New EventClassModule
Public Sub RegisterEventHandler()
Set ThisWordApp.App = Word.Application
End Sub
Code 2: Put this code into a normal module (not a class module).
The event DocumentBeforePrint will work after you registered the event handler by running RegisterEventHandler, this is recommended to run whenever the document is opened. Therefore we use the Document.Open event in ThisDocument:
Option Explicit
Private Sub Document_Open()
RegisterEventHandler
End Sub
Code 3: Put this code into "ThisDocument".
Then save, close and re-open your document. If you print it now, the event DocumentBeforePrint will execute right before printing.
Edit according comment:
Image 1: Make sure your class module is named correctly.

How to ask for confirmation before allowing a Word document to close?

I work with 2 different keyboard layouts (qwerty and azerty), and am constantly switching between the two using Alt-Shift. Sometimes when I reach for Ctrl-Z to undo, I get instead Ctrl-W which closes the document. Generally speaking I would in these situations get a Save Prompt, which would alert me to my mistake. However, I am now using OneDrive, with Autosave on the documents I'm working on. As a result, there is never this save prompt. The document is instantly closed and, worse, the undo that I was trying to effect is no longer present when the document is re-opened.
I would like to use VBA attached to the Normal Template, such that, on closing any document created with the VBA template, I will check to see if Autosave is turned on, and if it is, confirm before closing with a messagebox.
Obviously if the user doesn't confirm (e.g. chooses Cancel) then the document should not be closed.
Initially I put my code on Document_Close, but soon realised that here it's too late to Cancel the close. This is no good to me.
Then, based on some online code, I put my code in a class module (EventClassModule). In the ThisDocument module, I initiate the class, and activate the event handler.
My code doesn't ever seem to run, or in anycase, breakpoints don't kick in.
I'm a little unsure of where Normal stops and my normal document begins...
In ThisDocument of Normal Template, I have this VBA
Dim X As New EventClassModule
Sub Register_Event_Handler()
Set X.App = Word.Application
End Sub
Private Sub Document_Open()
Register_Event_Handler
End Sub
And I have a class module called EventClassModule with the following
Public WithEvents App As Word.Application
Private Sub App_DocumentBeforeClose(ByVal Doc As Document, Cancel As Boolean)
Dim res As VbMsgBoxResult
If Me.AutoSaveOn Then
res = MsgBox("OK to Confirm", vbOKCancel, "Closing Document")
If res = vbCancel Then
Cancel = True
End If
End If
End Sub
I would like a prompt to confirm saving, any time a document is closed and the autosave option is turned off.
The Document_Open event handler will only fire if the Normal template is opened via File | Open. To get code to respond when starting Word you need to use an AutoExec routine. Simply rename your routine as below. You can find further info on Auto macros here
Public Sub AutoExec()
Register_Event_Handler
End Sub
Here is an easy way, include a method like this:
Public Sub DocClose()
' Disables Ctrl + W (but not other close methods, e.g. Alt + F4, menus, [X])
' Your code here:
ActiveDocument.Close
End Sub
Basically there are some method names that are used internally by MS-Word, and if you include them in your code they will prevent the default action. If you leave the sub empty it will effectively disable Ctrl + W.
See here for more information: Reserved method names in MS Word VBA
Advantage 1 of this technique
If you use Public WithEvents App As Word.Application and your project gets reset for any reason, and fails to restart... App will be Nothing and none of the events will fire.
Advantage 2 of this technique
On the occasions that you actually want to close a document... with this technique you wont get bugged by a (soon to become) annoying confirmation message - just sayin ;-)

Outlook Macro to delete old messages when a new message with same subject arrives

Am trying to write a outlook VB macro, to achieve following:
Triggers when a new email arrives.
Go to a folder inside Inbox - temp1.
Check if there is an existing email which matches the subject of
this new email.
Delete the old email.
Code:
Option Explicit
Private objNS As Outlook.NameSpace
Private WithEvents objItems As Outlook.Items
Private Sub Application_Start()
Dim olApp As Outlook.Application
Dim objWatchFolder As Outlook.Folder
Set olApp = Outlook.Application
Set objNS = Application.GetNamespace("MAPI")
'Set the folder and items to watch:
Set objWatchFolder = objNS.GetDefaultFolder(olFolderInbox).Folders("temp1")
Set objItems = objWatchFolder.Items
Set objWatchFolder = Nothing
End Sub
Private Sub objItems_ItemAdd(ByVal Item As Object)
Dim intCount As Integer
Dim objVariant As Variant
For intCount = objItems.Count To 1 Step -1
Set objVariant = objItems.Item(intCount)
If objVariant.Subject = Item.Subject And objVariant.SentOn < Item.SentOn
Then
objVariant.Delete
Else
End If
Next
End Sub
Issue:
Macro not getting triggered.
Notes:
Have Trust center settings updated to enable macros.
Have added this code in Class Module
When I do F5, it doesn't show any MACRO that it can run.
Seeking some expert help pls!
(1) You need to handle the NewMailEx event of the Application class which is fired when a new item is received in the Inbox. 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. Use this method with caution to minimize the impact on Outlook performance. However, depending on the setup on the client computer, after a new message arrives in the Inbox, processes like spam filtering and client rules that move the new message from the Inbox to another folder can occur asynchronously. You should not assume that after these events fire, you will always get a one-item increase in the number of items in the Inbox.
(2) It looks like you already know how to get the a subfolder of Inbox:
Set objWatchFolder = objNS.GetDefaultFolder(olFolderInbox).Folders("temp1")
(3) To find items with the same subject you need to use the Find/FindNext or Restrict methods of the Items class instead of iterating over all items in the folder. Read more about these methods in the following articles:
How To: Use Find and FindNext methods to retrieve Outlook mail items from a folder (C#, VB.NET)
How To: Use Restrict method to retrieve Outlook mail items from a folder
Also if you need to find items in multiple folders you may find the AdvancedSearch method of the Application class helpful. The key benefits of using the AdvancedSearch method in Outlook are:
The search is performed in another thread. You don’t need to run another thread manually since the AdvancedSearch method runs it automatically in the background.
Possibility to search for any item types: mail, appointment, calendar, notes etc. in any location, i.e. beyond the scope of a certain folder. The Restrict and Find/FindNext methods can be applied to a particular Items collection (see the Items property of the Folder class in Outlook).
Full support for DASL queries (custom properties can be used for searching too). You can read more about this in the Filtering article in MSDN. To improve the search performance, Instant Search keywords can be used if Instant Search is enabled for the store (see the IsInstantSearchEnabled property of the Store class).
You can stop the search process at any moment using the Stop method of the Search class.
See Advanced search in Outlook programmatically: C#, VB.NET for more information.
(4) Use the Delete method for removing items.
Items.ItemAdd Event (Outlook) describes how to apply the ItemAdd event in a Class module. You would then use Application_Startup in ThisOutlookSession to initialize objItems.
What you have is code for the ThisOutlookSession module.
You are watching the ItemAdd event on the temp1 folder, not the Inbox.

How can I implement the PropertyChange event?

I wish to get the details of what has been changed in a MailItem.
I have been able to get ItemChange to trigger based upon Application.Session.Folders("TargetFolder") to a variable as such:
Private Sub olInvMbxItems_ItemChange(ByVal X As Object).
I would like to know the property changed in X. If I pass X to an global variable for Private Sub X_PropertyChange(ByVal x As Object), it will miss the first iteration as X was not initialized on the first pass of ItemChange.
How can I monitor a folder of MailItems to detect Category changes. Whilst ItemChange does this, it gives duplication of action, if I look for specific categories, as many changes trigger ItemChange as mentioned here:
Handle ItemChange event when outlook appointments are dismissed
and here:
Outlook Macro that will copy an email I flag and put it in a folder
The binary flag for the UserProperties in the second item will not function as it is not a one-off event.
Outlook Events VBA says to use PropertyChange but doesn't provide a technique for implementation.
There is no way to do that - even on the MAPI level, the store provider does not keep track on what changed. Your only solution is to compare the old (saved elsewhere by you) and new values to see what changed.
Here is a method that works for a single selection. Refinement yet needed, but this is a starting point:
Private WithEvents olExplorer As Outlook.Explorer
Private olCurSel As Selection
Private WithEvents olCurSelItem As Outlook.MailItem
Private Sub olExplorer_SelectionChange()
Set olCurSel = olExplorer.Selection
Set olCurSelItem = Nothing
Dim i As Long
For i = 1 To olCurSel.Count
If TypeName(olCurSel.Item(i)) = "MailItem" Then
Set olCurSelItem = olCurSel.Item(i)
End If
Next i
End Sub
Private Sub olCurSelItem_PropertyChange(ByVal Name As String)
Debug.Print Name; " is what changed!"
End Sub
Using Outlook.Explorer.Selection we can know that an item has been selected. We can then assign that item to and Outlook.MailItem conditionally and use the PropertyChange event of that Outlook.MailItem trigger the action we wish to take.
Problems:
Does not handle multiple selections
SelectionChange is triggered by the Reading Pane on each selection as well. Thus it is fired twice if the reading pane is open. As written above, olCurSelItem is set twice each SelectionChange.
This is only triggered by local changes. Other systems with access to the mailbox may change the item and it will not trigger the action.

Make Outlook AppointmentItem Read-Only

I am creating outlook appointment items programmatically using VBA in MS Access and the Outlook Object Model (though the language shouldn't matter).
Items are added to multiple calendars belonging to a single user that other users are given read/write permissions to. The users have no reason to create or edit appointments on the calendar using Outlook. Appointment data is then stored in backend tables. Essentially, Outlook is being used as my "calendar view."
I am having major issues, however, with users changing appointment items directly in Outlook, which in turn do not update in my backend.
I would love an updateable "ReadOnly" property that can be set per appointment item and that disallows changes unless set back to False...but don't think one exists. Any suggestions?
Things I've tried or dismissed as solutions:
Reminding users of the rules.
Script that finds all mismatched items - this works but is not practical.
Custom Outlook form that doesn't allow edits - doesn't prevent users from dragging appointment around.
UPDATE:
Using the suggestion by nemmy below, I have manged to get this far. This only works if the user selects the appointment before changing anything. It does not work if the appointment is selected and dragged in the same click.
Private WithEvents objExplorer As Outlook.Explorer
Private WithEvents appt As Outlook.AppointmentItem
Public Sub Application_Startup()
Set objExplorer = Application.ActiveExplorer
End Sub
Private Sub objExplorer_SelectionChange()
If objExplorer.CurrentFolder.DefaultItemType = olAppointmentItem Then
If objExplorer.Selection.Count > 0 Then
Set appt = objExplorer.Selection(1)
End If
End If
End Sub
Private Sub appt_Write(Cancel As Boolean)
If Not appt.Mileage = "" Then 'This appointment was added by my program
MsgBox ("Do not change appointments directly in Outlook!")
Cancel = True
appt.Close (olDiscard)
End If
End Sub
Can you hook into the Write Event of appointment items? You could prevent changes being made that way. Something like below might work (Disclaimer not tested):
Public WithEvents myItem As Outlook.AppointmentItem
Sub Initialize_handler()
Set myItem = Application.GetNamespace("MAPI").GetDefaultFolder(olFolderCalendar).Items("Your Appointment")
End Sub
Private Sub myItem_Write(Cancel as boolean)
Cancel=true
End Sub
The problem you have is that the people have write access, can you or is it possible to only give them read access? If that is not acceptable, then my answer is you cannot or should not stop them from changing the items. You need to deal with it. This is what I do.
So when you create the calendar item give it a unique ID for example the ID from your backend table row. Add this to a property of the calendar item like the mileage property.
Now just create an update method which loops through all current calendar items in your table and get them from outlook with the ID, check it has not changed and if it has update your table.
Alternatively and given your comment below;
In my opinion you must control outlook. As such nemmy is on the right track you need to hook into the outlook object probably with the use of an outlook addin. Then you need to get each appointment item that the user opens and check if it has a mileage ID. If it does you either need to tell them to change this in your data base and not outlook, or you need to get the events relevant indicating changes to the appointment item and wait for it to be changed. Then send these changes from outlook to your database.