An Outlook user, KT, wanted to defer delivery of messages sent after 6PM, sending them at 7 AM the next day. This is possible to do using an ItemSend macro.
If it's after 6PM or before 7AM, the message is held until 7AM, then sent. Because this is an Outlook script, it only works in Outlook. It will not affect messages sent using smartphones or other devices.
May 6 2017: Edited the macros to properly move early morning messages ahead a few hours, not 1 day and to account for messages sent Sat or Sun.
Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean) ' If after 6PM If Now() > DateSerial(Year(Now), Month(Now), Day(Now)) + #5:59:00 PM# Then SendAt = DateSerial(Year(Now), Month(Now), Day(Now) + 1) + #7:00:00 AM# ' If before 7AM ElseIf Now() < DateSerial(Year(Now), Month(Now), Day(Now)) + #6:59:00 AM# Then SendAt = DateSerial(Year(Now), Month(Now), Day(Now)) + #7:00:00 AM# End If Item.DeferredDeliveryTime = SendAt End Sub
If you need to skip weekends (or other days of the week), check the name of the day and add additional time to the SendAt time.
Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean) Dim dayname As String ' If after 6PM If Now() > DateSerial(Year(Now), Month(Now), Day(Now)) + #5:59:00 PM# Then sendat = DateSerial(Year(Now), Month(Now), Day(Now) + 1) + #7:00:00 AM# ' If before 7AM ElseIf Now() < DateSerial(Year(Now), Month(Now), Day(Now)) + #6:59:00 AM# Then sendat = DateSerial(Year(Now), Month(Now), Day(Now)) + #7:00:00 AM# ' We'll test the date of all messages ElseIf WeekdayName(Weekday(Now())) = "Saturday" Or WeekdayName(Weekday(Now())) = "Sunday" Then ' this will be changed by the next part if a weekend sendat = DateSerial(Year(Now), Month(Now), Day(Now)) + #11:00:00 PM# End If dayname = WeekdayName(Weekday(sendat)) Select Case dayname Case "Saturday" sendat = DateSerial(Year(Now), Month(Now), Day(Now) + 2) + #7:00:00 AM# Case "Sunday" sendat = DateSerial(Year(Now), Month(Now), Day(Now) + 1) + #7:00:00 AM# End Select Item.DeferredDeliveryTime = sendat Debug.Print Now(), dayname, sendat End Sub
Only Delay message Sent to Specific Addresses
Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean) Const PR_SMTP_ADDRESS As String = "http://schemas.microsoft.com/mapi/proptag/0x39FE001E" Set recips = Item.Recipients For Each recip In recips Set pa = recip.PropertyAccessor Address = LCase(pa.GetProperty(PR_SMTP_ADDRESS)) lLen = Len(Address) - InStrRev(Address, "@") Select Case Right(Address, lLen) ' add additional addresses as neeed, using quotes and comma separator Case "mcarnar@domain.com", "bburns@domain.com", "rchildars@domain.com", "curry@domain.com" Case Else ' remove case else line to be warned when sending to the addresses strMsg = strMsg & " " & Address & vbNewLine End Select Next ' using <> delays these addresses only; ' use = to delay all but these addresses If strMsg <> "" Then ' If after 6PM If Now() > DateSerial(Year(Now), Month(Now), Day(Now)) + #5:59:00 PM# Then SendAt = DateSerial(Year(Now), Month(Now), Day(Now) + 1) + #7:00:00 AM# ' If before 7AM ElseIf Now() < DateSerial(Year(Now), Month(Now), Day(Now)) + #6:59:00 AM# Then SendAt = DateSerial(Year(Now), Month(Now), Day(Now)) + #7:00:00 AM# End If Item.DeferredDeliveryTime = SendAt End If End Sub
How to use the macro
First: You will need macro security set to low during testing.
To check your macro security in Outlook 2010 or 2013, go to File, Options, Trust Center and open Trust Center Settings, and change the Macro Settings. In Outlook 2007 and older, it’s at Tools, Macro Security. If Outlook tells you it needs to be restarted, close and reopen Outlook. Note: after you test the macro and see that it works, you can either leave macro security set to low or sign the macro.
Now open the VBA Editor by pressing Alt+F11 on your keyboard.
To use the macro code in ThisOutlookSession:
- Expand Project1 and double click on ThisOutlookSession.
- Copy then paste the macro into ThisOutlookSession. (Click within the code, Select All using Ctrl+A, Ctrl+C to copy, Ctrl+V to paste.)
More information as well as screenshots are at How to use the VBA Editor.
There exists the add-in for Outlook named OffHours that ensures that emails you write after business hours and on weekends are delayed and will only be sent at the start of the next business day: https://www.ivasoft.com/offhoursaddin.shtml
This is super - thank you so much! All our student email addresses start with "ST0000". I would like to delay delivery to students only between 3pm-8:30am and at weekends for any emails sent to to addresses beginning with/containing "ST0000". Would this be possible? My knowledge of VBA is relatively basic.
Hi Diane & thanks a lot. Two questions:
Thanks again.
On the sent time macro - the one in your links sends all drafts when the reminder fires. I have similar macro that would sends drafts at different times. You put the time you want to send them messages in the subject and the macro runs on s schedule - anything with a date older than that will be sent when the macro runs.
This gives me an idea - instead of looking at the subject, add a defer until time and look at that in the draft. Off to find the macro and tweak it. :)
Thank you so much Diane. Your post did exactly what I needed.
It was a while since Dom asked two years ago about SendAt not being defined. The trick is to define SendAt like this:
Dim SendAt As Date
The problem is caused by Option Explicit at the top (which is a good idea and should not be removed according to me)
Would this be a good way to address the issues of sending e-mails on Friday and Saturday from 6PM to 11:59PM?
Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)
Dim dayname As String
' If Friday after 6PM
If WeekdayName(Weekday(Now())) = "Friday" And Now() > DateSerial(Year(Now), Month(Now), Day(Now)) + #5:59:00 PM# Then
sendat = DateSerial(Year(Now), Month(Now), Day(Now) + 3) + #8:00:00 AM#
' If Saturday
ElseIf WeekdayName(Weekday(Now())) = "Saturday" Then
sendat = DateSerial(Year(Now), Month(Now), Day(Now) + 2) + #8:00:00 AM#
' If Sunday
ElseIf WeekdayName(Weekday(Now())) = "Sunday" Then
sendat = DateSerial(Year(Now), Month(Now), Day(Now) + 1) + #8:00:00 AM#
' If other week days after 6PM
ElseIf Now() > DateSerial(Year(Now), Month(Now), Day(Now)) + #5:59:00 PM# Then
sendat = DateSerial(Year(Now), Month(Now), Day(Now) + 1) + #8:00:00 AM#
' If other week days before 8AM
ElseIf Now() < DateSerial(Year(Now), Month(Now), Day(Now)) + #7:59:00 AM# Then
sendat = DateSerial(Year(Now), Month(Now), Day(Now)) + #8:00:00 AM#
End If
Item.DeferredDeliveryTime = sendat
End Sub
That should work. (I didn't test it though - but it looks good.)
Hi. It helped me a lot. Thank you
Hi Diane, I am just starting out with Macros -- have never had to do this before. This is exactly what I am looking for. I'm using Outlook 2016. Even though I copy/paste this macro into ThisOutlookSession, when I hit play, it brings up the Macros dialog box (with run, cancel, step intro) and there is nothing to select there. I am missing a step somehow. What am I doing wrong?
THis is my comment- Please reject it because it is awaiting moderation -- it seems to be working now -- I have a different question that I am going to post in your forums, which I just saw now.
Hi Diane,
Thanks a lot for the great article. It is a bit older, but I still have a question. I tried your macro and it works perfectly, but the time the email is sent is still the time when I hit send. Meaning the receipient sees the time when I actually sent the message. Is there a way to set the time displayed in the message header to match the time it actually leaves my outbox or at least when the timer expires?
Thanks a lot,
Best Regards
Andreas
No, not using this method. If you use an appointment reminder to trigger the send, it will have the current time. The reminder will trigger a macro that sends a draft.
https://www.slipstick.com/developer/send-email-outlook-reminders-fires/#draft