Save Appointment to Exchange Public Calendar Folder - vba

I would like to save and share important items across user accounts running on an Exchange 2016 server. This is setup via Public Folders on the server.
How do I specify the appointment items created go to the folder in the root public folder that is designated for calendar items?
I created all the necessary public folder items on the Exchange 2016 server and have them appearing across multiple accounts that have been designated the required permissions.
I have the appointment item populated with some basic information and I would like it to go to said folder once the user populates any additional fields and clicks the save/send button.
The folder structure for the public folders:
All Public Folders
Company Name sub-folder (Public Folder Mailbox)
Mail
Contacts
Calendars
Public Sub CreateAppointment()
Dim objOL As Outlook.Application
Dim objNS As Outlook.NameSpace
Dim objMsg As Outlook.MailItem 'Message Object
Dim objCalAppt As Outlook.AppointmentItem
Dim objPublicFolderRoot As Outlook.Folder
Dim objDKRRFolder As Outlook.Folder
Dim objApptFolder As Outlook.Folder
Set objNS = Application.GetNamespace("MAPI")
Set objCalAppt = Application.CreateItem(olAppointmentItem)
Set objMsg = Application.ActiveExplorer().Selection(1)
Set objPublicFolderRoot = objNS.GetDefaultFolder(olPublicFoldersAllPublicFolders)
Set objCompanyFolder = objPublicFolderRoot.Folders("Company_Shared")
Set objApptFolder = objCompanyFolder.Folders("Calendars")
With objCalAppt
.MeetingStatus = olNonMeeting 'Not an invitation
.Subject = objMsg.Subject
.Start = objMsg.SentOn
.Duration = 120
End With
objCalAppt.Display
End Sub
If I manually send/save the item, it does not appear in the folder, and it also doesn't appear in the user's calendar.

Instead of creating a "lonely" appointment item, try to create an additional item within the appropriate calendar instead:
Public Sub CreateAppointment()
Dim objOL As Outlook.Application
Dim objNS As Outlook.NameSpace
Dim objMsg As Outlook.MailItem 'Message Object
Dim objCalAppt As Outlook.AppointmentItem
Dim objPublicFolderRoot As Outlook.Folder
Dim objCompanyFolder As Outlook.Folder
Dim objApptFolder As Outlook.Folder
Set objNS = Application.GetNamespace("MAPI")
Set objMsg = Application.ActiveExplorer().Selection(1)
Set objPublicFolderRoot = objNS.GetDefaultFolder(olPublicFoldersAllPublicFolders)
Set objCompanyFolder = objPublicFolderRoot.Folders("Company_Shared")
Set objApptFolder = objCompanyFolder.Folders("Calendars")
Set objCalAppt = objApptFolder.Items.Add(olAppointmentItem)
With objCalAppt
.MeetingStatus = olNonMeeting 'Not an invitation
.Subject = objMsg.Subject
.Start = objMsg.SentOn
.Duration = 120
End With
objCalAppt.Display
End Sub
As the code row Set objMsg = Application.ActiveExplorer().Selection(1) only works, if the user currently selected an email item, I suggest to verify that additionally:
Dim objSel As Outlook.Selection
Set objSel = Application.ActiveExplorer.Selection
If objSel.Count > 0 Then
If objSel(1).Class = olMail Then
Set objMsg = objSel(1)
Else
MsgBox "Works only on selected email."
End If
Else
MsgBox "Works only on selected email."
End If

Related

Macro runs while debugging but not when event happens

I am trying to create a tool that both acts on new emails while Outlook is open as well as on emails received while the Outlook application is closed.
This is what I have so far:
-One sub that creates a note item upon quitting the app.
-One sub that filters emails in the inbox by the their received time.
The second sub is working when I debug (but also infinitely loops and reprocesses the new emails over and over), but does not work (as in does not take any action on the new emails) when I launch the application, expecting the startup event to trigger the sub.
Microsoft Outlook Objects/"ThisOutlookSession"):
Option Explicit
Private StartupTrigger As SaveAttachment1
Private ShutdownTrigger As Class2
Private Sub Application_Startup()
Set StartupTrigger = New SaveAttachment1
StartupTrigger.SaveAttachment1_Initialize
StartupTrigger.Process_New_Items
End Sub
Private Sub Application_Quit()
Set ShutdownTrigger = New Class2
ShutdownTrigger.ExitApp
End Sub
Class Modules:
Class2
Public Sub ExitApp()
Dim olApp As Outlook.Application
Dim olNS As Outlook.NameSpace
Dim olNoteIt As Outlook.NoteItem
Dim myFol As Outlook.Folder
Dim myFilter As String
Dim i As Object
Set olApp = Outlook.Application
Set olNS = olApp.GetNamespace("MAPI")
Set myFol = olNS.GetDefaultFolder(olFolderNotes) '.Folders("Attachment Filters")
myFilter = "[Subject] = 'App Close Time'"
For Each i In myFol.Items.Restrict(myFilter)
i.Delete
Next i
Set olNoteIt = olApp.CreateItem(olNoteItem)
With olNoteIt
.Body = "App Close Time"
'.Move myFol
End With
olNoteIt.Save
End Sub
SaveAttachment1
Option Explicit
Public WithEvents olItems As Outlook.Items
Public Sub SaveAttachment1_Initialize()
Dim olApp As Outlook.Application
Dim olNS As Outlook.NameSpace
Set olApp = Outlook.Application
Set olNS = olApp.GetNamespace("MAPI")
Set olItems = olNS.GetDefaultFolder(olFolderInbox).Folders("User ID (DMs) - Wells Fargo").Items
End Sub
Public Sub Process_New_Items()
Dim olApp As Outlook.Application
Dim olNS As Outlook.NameSpace
Dim filterString As String
Dim olFol As Outlook.Folder
Dim i As Object
Dim olmi As Outlook.MailItem
Dim cfilter As Object
Dim my_olMail As MailItem
Dim dmi As MailItem
Dim utcdate As Date
Dim filterfolder As Outlook.Folder
Dim SMTPAddress As String
Dim olAtt As Outlook.Attachment
Dim fso As Object
Dim olAttFilter As String
Dim timeFol As Outlook.Folder
Dim lastclose As String
Dim timeFilter As String
Set olApp = Outlook.Application
Set olNS = olApp.GetNamespace("MAPI")
Set filterfolder = olNS.GetDefaultFolder(olFolderContacts).Folders("FilterContacts")
Set dmi = olApp.CreateItem(olMailItem)
Set timeFol = olNS.GetDefaultFolder(olFolderNotes)
timeFilter = "[Subject] = 'App Close Time'"
For Each i In timeFol.Items.Restrict(timeFilter)
lastclose = i.CreationTime
Next i
utcdate = dmi.PropertyAccessor.LocalTimeToUTC(lastclose)
filterString = "#SQL=""urn:schemas:httpmail:datereceived"" >= '" & Format(utcdate, "dd mmm yyyy hh:mm") & "'"
Set fso = CreateObject("Scripting.FileSystemObject")
Set olFol = olNS.GetDefaultFolder(olFolderInbox)
For Each i In olFol.Items.Restrict(filterString)
If TypeName(i) = "MailItem" Then
If i.SenderEmailType = "EX" Then
SMTPAddress = i.Sender.GetExchangeUser.PrimarySmtpAddress
Else
SMTPAddress = i.SenderEmailAddress
End If
For Each cfilter In filterfolder.Items
If SMTPAddress = cfilter.JobTitle Then
If InStr(1, LCase(i.Subject), cfilter.BusinessTelephoneNumber) <> 0 Then
For Each olAtt In i.Attachments
If InStr(1, LCase(olAtt.FileName), cfilter.HomeTelephoneNumber) <> 0 Then
olAttFilter = fso.GetExtensionName(olAtt.FileName)
Select Case olAttFilter
Case cfilter.BusinessFaxNumber
olAtt.SaveAsFile cfilter.MobileTelephoneNumber & "\" & olAtt.FileName
Case Else
End Select
Else: End If
Next olAtt
Else: End If
Else: End If
Next cfilter
End If
Next i
End Sub
The "Process_New_Items()" sub is admittedly a mess, but essentially, it is referencing an Outlook contact item and uses the different fields of the contact item to filter the new emails, and then save the attachment if the email meets all the filter criteria.
Thanks!
Adam
acts on new emails while Outlook is open as well as on emails received while the Outlook application is closed
First, to handle new emails I'd recommend using the Application.NewMailEx event which is fired when a new message arrives in the Inbox and before client rule processing occurs. Use the Entry ID represented by the EntryIDCollection argument to call the NameSpace.GetItemFromID method and process the item. This event fires 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.
Another possible alternative is to using ItemAdd event on the Inbox folder.
You may find the following series of articles helpful:
Outlook NewMail event unleashed: the challenge (NewMail, NewMailEx, ItemAdd)
Outlook NewMail event: solution options
Outlook NewMail event and Extended MAPI: C# example
Outlook NewMail unleashed: writing a working solution (C# example)
Second, when Outlook is closed the OOM is useless.

Add event to other user's Outlook calendar

Our email system is being updated to Exchange 365. I have a database that was adding calendar events (employee time off) to a public folder.
Well, the updated Exchange does not use public folders. So, we created a user and shared the calendar, and now I'm trying to figure out the code to add/change/delete the event to/from another user's calendar through Access 2016 (and 2012 hopefully).
The code below is me just trying to figure out how to add so has no error checking. In fact, I created a database just for this.
I did figure out how to add it to my own calendar, but it will not work adding it to the new Exchange 365 user calendar. Here is my code:
Private Sub Command15_Click()
Dim outMail As Outlook.AppointmentItem
Dim objNS As Outlook.NameSpace
Dim objFolder As Outlook.MAPIFolder 'get name of other persons folder
Dim objRecip As Outlook.Recipient 'other persons name
Dim strName As String 'the name or email of the persons folder
Dim objAppt As Outlook.AppointmentItem
Dim objApp As Outlook.Application
On Error Resume Next
' name of person whose Calendar you want to use - right
strName = "janet 2"
Set objNS = objApp.GetNamespace("MAPI")
Set objRecip = objNS.CreateRecipient(strName)
Set objFolder = objNS.GetSharedDefaultFolder(objRecip, olFolderCalendar)
'Set outMail = Outlook.CreateItem(olAppointmentItem)
Set outMail = objFolder.Items.Add
outMail.Subject = "test"
outMail.Location = ""
outMail.MeetingStatus = olMeeting
outMail.Start = Me.BegDate
outMail.End = Me.BegTime
outMail.RequiredAttendees = strName
outMail.Body = "test message"
outMail.Save
'Set outMail = Nothing
End Sub
I got it to work (sort of). I changed back Set OutMail to what I originally had:
Set OutMail = Outlook.CreateItem(olAppointmentItem)
And I changed Outmail.Save to Outmail.Send.
It now puts it in the other user's calendar, but as unaccepted. I need it to go in as Accepted. I'm going to research this now.
Whole code that works:
Dim outMail As Outlook.AppointmentItem ' meeting or one-time appointment in Calendar folder
Dim objNS As Outlook.NameSpace ' accessing data sources owned by other users
Dim objFolder As Outlook.MAPIFolder 'get name of other persons folder
Dim objRecip As Outlook.Recipient ' Other persons name
Dim strName As String ' the name or email of the persons folder
Dim objAppt As Outlook.AppointmentItem
Dim objApp As Outlook.Application
'name of person whose calendar you want to use
strName = "ICT Time Off"
Set objApp = GetObject(, "Outlook.Application") 'Bind to existing instance of Outlook
Set objNS = objApp.GetNamespace("MAPI")
Set objRecip = objNS.CreateRecipient(strName)
Set objFolder = objNS.GetSharedDefaultFolder(objRecip, olFolderCalendar)
'Set outMail = Outlook.CreateItem(olAppointmentItem)
Set outMail = objFolder.Items.Add
outMail.Subject = "test"
outMail.Location = ""
outMail.MeetingStatus = olMeeting
outMail.Start = Me.BegDate
outMail.End = Me.EndDate
outMail.RequiredAttendees = strName
outMail.Body = "test message"
outMail.Save

How do I select an archive folder?

I have an email account "Fred.Smith#domain.co.uk" (domain being made up).
Outlook shows an archive named " Archive - Fred.Smith#domain.co.uk" where Outlook automatically moves emails after a certain period.
Current code:
Set olRecip = olNS.CreateRecipient("Archive - Fred.Smith#domain.co.uk")
olRecip.Resolve
Set olFolder = olNS.GetSharedDefaultFolder(olRecip, olFolderInbox)
This opens the main inbox. How do I select the archive folder?
"Archive" folder is usually at the root level - like inbox
in that case:
Sub ArchiveItems()
' Moves each of the selected items on the screen to an Archive folder.
Dim olApp As New Outlook.Application
Dim olExp As Outlook.Explorer
Dim olSel As Outlook.Selection
Dim olNameSpace As Outlook.NameSpace
Dim olArchive As Outlook.Folder
Dim intItem As Integer
Set olExp = olApp.ActiveExplorer
Set olSel = olExp.Selection
Set olNameSpace = olApp.GetNamespace("MAPI")
Set olArchive = olNameSpace.Folders("myMail#mail.com").Folders("Archive")
For intItem = 1 To olSel.Count
olSel.Item(intItem).Move olArchive
Next intItem
End Sub
to get Inbox you could use default access:
Dim olInbox As Outlook.Folder
Set olInbox = olNameSpace.GetDefaultFolder(olFolderInbox)
Note - This will get you the default Inbox folder, if you have a few accounts in outlook you should verify it's really the folder you want - or use the mail specific approach like in Archive folder above
For Debugging - if you want to check all available subfolders
For i = 1 To olInbox.Folders.Count
Debug.Print olInbox.Folders(i).Name
Next i
Should be
Dim ARCHIVE_FOLDER As Outlook.MAPIFolder
Set ARCHIVE_FOLDER = olNs.Folders("Archive - Fred.Smith#domain.co.uk")
Full Example
Option Explicit
Public Sub Example()
Dim olNs As Outlook.NameSpace
Dim ARCHIVE_FOLDER As Outlook.MAPIFolder
Dim Items As Outlook.Items
Dim i As Long
Set olNs = Application.Session
Dim ARCHIVE_FOLDER As Outlook.MAPIFolder
Set ARCHIVE_FOLDER = olNs.Folders("Archive - Fred.Smith#domain.co.uk") _
.Folders("Inbox")
Debug.Print ARCHIVE_FOLDER.Name
Debug.Print ARCHIVE_FOLDER.FolderPath
Debug.Print ARCHIVE_FOLDER.Store.DisplayName
ARCHIVE_FOLDER.Display
Set Items = ARCHIVE_FOLDER.Items
For i = Items.Count To 1 Step -1
DoEvents
Debug.Print Items(i).Subject
Next
End Sub
MAPIFolder Object

MS Access - add appointment event to shared Outlook Calendar

I want to add an appointment to a shared Outlook calendar. I know how to add to other people's calendars from MS Access, but I'm having trouble with shared calendars. The creator of the calendar also has their own personal calendar. All of my previous attempts have just added to their personal calendar.
Here's my code... I've tried gathering code on various websites and I'm just stuck. I appreciate any help.
Private Sub Add_to_Shared_Calendar_Click()
Dim outMail As Outlook.AppointmentItem
Dim objNS As Outlook.NameSpace
Dim objFolder As Outlook.MAPIFolder 'get name of other persons folder
Dim objRecip As Outlook.Recipient 'other persons name
Dim strName As String 'the name or email of the persons folder
Dim objAppt As Outlook.AppointmentItem
Dim objApp As Outlook.Application
On Error Resume Next
' name of person whose Calendar you want to use - right?
strName = "John Smith - Project Name Shared Calendar"
Set objNS = objApp.GetNamespace("MAPI")
Set objRecip = objNS.CreateRecipient(strName)
Set objFolder = objNS.GetSharedDefaultFolder(objRecip, olFolderCalendar)
Set outMail = Outlook.CreateItem(olAppointmentItem)
outMail.Subject = "test"
outMail.Location = ""
outMail.MeetingStatus = olMeeting
outMail.Start = Me.dateofevent
outMail.End = Me.TimeofEvent
outMail.RequiredAttendees = strName
outMail.Body = "test message"
outMail.Send
Set outMail = Nothing
End Sub
Replace the lines
outMail = Outlook.CreateItem(olAppointmentItem)
...
outMail.Send
with
outMail = objFolder.Items.Add
...
outMail.Save

Getting an EntryID after an object is moved

Summary
I'm trying to add hyperlinks to tasks created from emails that I have moved to another folder.
The goal is to have the task contain a hyperlink to the Outlook item that was moved to a "Processed Email" folder".
Problem
I don't understand how to move a MailItem and then get its new EntryID after it moves.
The "naive" way doesn't work. After using the Move method to move a MailItem object, the EntryID property does not reflect a change in ID.
Details
Creating a hyperlink to an Outlook item using the format outlook:<EntryID> is easy enough if the Outlook item remains in the Inbox, since I can just get the EntryID of the object that I am linking to. However, Outlook changes the EntryID when an object is moved.
I want to understand how to get the updated ID so that I can construct an accurate link.
Example
The message boxes show the EntryID property of objMail returns the same value despite the fact that the object has moved. However, running a separate macro on the mail in the destination folder confirms that the EntryID has changed with the move.
Sub MoveObject(objItem As Object)
Select Case objItem.Class
Case olMail
Dim objMail As MailItem
Set objMail = objItem
MsgBox (objMail.EntryID)
Dim inBox As Outlook.MAPIFolder
Set inBox = Application.ActiveExplorer().Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox)
Dim destFolder As Outlook.MAPIFolder
Set destFolder = inBox.Folders("Processed Email")
If (Application.ActiveExplorer().CurrentFolder.Name <> destFolder.Name) Then
objMail.Move destFolder
End If
MsgBox (objMail.EntryID)
End Select
End Sub
The Move method of the MailItem class returns an object that represents the item which has been moved to the designated folder. You need to check out the EntryID value of the returned object, not the source one.
Anyway, you may consider handling the ItemAdd event of the target folder to make sure that an updated entry ID value is used all the time.
Sub MoveItems()
Dim myNameSpace As Outlook.NameSpace
Dim myInbox As Outlook.Folder
Dim myDestFolder As Outlook.Folder
Dim myItems As Outlook.Items
Dim myItem As Object
Set myNameSpace = Application.GetNamespace("MAPI")
Set myInbox = myNameSpace.GetDefaultFolder(olFolderInbox)
Set myItems = myInbox.Items
Set myDestFolder = myInbox.Folders("Personal Mail")
Set myItem = myItems.Find("[SenderName] = 'Eugene Astafiev'")
While TypeName(myItem) <> "Nothing"
myItem.Move myDestFolder
Set myItem = myItems.FindNext
Wend
End Sub
Hello can you please elaborate your answer I am not able to understand it.
Anyway, you may consider handling the ItemAdd event of the target folder to make sure that an updated entry ID value is used all the time.
Here is my code and I need EntryID after moving.
Sub Movetest1()
Dim olApp As Outlook.Application
Dim olns As Outlook.NameSpace
Dim Fld As Folder
Dim ofSubO As Outlook.MAPIFolder
Dim myDestFolder As Outlook.Folder
Dim ofolders As Outlook.Folders
Dim objItems As Outlook.Items
Dim myRestrictItems As Outlook.Items
Dim i As Long
Dim myitem As Object
' Dim MailItem As Microsoft.Office.Interop.Outlook.MailItem
Dim MailItem, moveditem As Outlook.MailItem
Dim eid As String
Dim sid As Variant
Dim newEID As String
'---------------------------------------------------------------------------------------------------------
Set olApp = New Outlook.Application
Set olns = olApp.GetNamespace("MAPI")
For Each Fld In olns.Folders
If Fld.Name = "GSS Payables" Then
'
' MsgBox Fld.Name
' Debug.Print " - "; Fld.EntryID
Set Fld = olns.GetFolderFromID("000000009DA6D76FBE7A58489450CDF6094F592A0100A2457DC435B22448A832DB721D8185B1000000B6207D0000").Folders("Inbox")
Exit For
End If
Next
Set objItems = Fld.Items
eid = "000000009DA6D76FBE7A58489450CDF6094F592A0700A2457DC435B22448A832DB721D8185B1000000B620800000A2457DC435B22448A832DB721D8185B100007FF773270000"
sid = "000000009DA6D76FBE7A58489450CDF6094F592A0100A2457DC435B22448A832DB721D8185B1000000B6207D0000"
Set myDestFolder = Fld.Folders("Bhagyashri")
'Set myitem = objItems.Find("[SenderName]='Microsoft Outlook '")
Set MailItem = olns.GetItemFromID(eid)
Set moveditem = MailItem.Move(myDestFolder)
"giving error here
newID = moveditem.entryid
Debug.Print "newID -"; newID
' get mailitem.parent.storeid
MsgBox "done"
End
Use the following syntax:
Dim MoveToFolder As outlook.MAPIFolder
Dim MyItem As outlook.MailItem
Dim NewEntryID As String
NewEntryID = MyItem.Move(MoveToFolder).ENTRYID
After MyItem.Move is executed the new ENTRYID will be returned to the NewEntryID variable.