I have a script within Outlook that moves an attachment to a folder. The folder is actually SharePoint Online so the file in the attachment is posted to our SharePoint site daily. It works perfectly Monday through Friday when the email is received.
Public Sub saveAttachtoDisk(itm As Outlook.MailItem)
Dim objAtt As Outlook.Attachment
Dim saveFolder As String
saveFolder = "C:\Users\xxx\SharePoint\Systems-Information Technolog - SYS 1\xxx"
For Each objAtt In itm.Attachments
objAtt.SaveAsFile saveFolder & "\" & objAtt.DisplayName
Set objAtt = Nothing
Next
End Sub
However, on Monday when the attachment is received and the rule is activated the attachment for Monday is posted to SharePoint, then the attachment for Sunday is posted and then the attachment for Saturday is posted making the only file available on SharePoint 2 days old.
I realize I can have the report stop arriving on Saturday and Sunday but can the script be modified to only retrieve the most recent attachment and then not run again? The reason this could be important is the attachment in the future could be created multiple times a day so I would need the most recent and no other to be posted.
Thanks for your help!
You can check out the RecievedTime property of the MailItem class which returns a Date indicating the date and time at which the item was received. So, you can check out the received time of each incoming email and save the attachment only if the mail item is the most recent one.
What kind of rule? After the message arrives? Keep in mind that if Outlook is not running, it will not receive new mail motivations (Saturday and Sunday). When Exchange cached store syncs with the server (on Monday), you will see new unread messages in the Inbox, but there will be no new mail motivations and the new mail rules will not fire.
You will need to change your code to run in response to the Items.ItemAdd event on the Inbox folder or run your code manually and process unread messages in the Inbox.
Related
I have a VB script that is triggered by a rule that saves the email's attachment to a specific folder. The rule runs ok for a period and then I receive the Outlook error message: "Unexpected error has occurred" and the rule is switched off.
Whilst I can't definitively say, from observations it seems that the error is more likely to occur when I receive more than one of these emails in the same send/receive batch. The attachments are usually 2MB to 5MB in size, and at times the Email Subject lines & file names on each of the consecutive emails' attachments can be the same. The same script on another rule which is usually only triggered once daily doesn't throw the error and continues working without interruption. This is occurring on multiple machines - so I deduce this might be related to the way Outlook handles these specific emails.
I don't know how to debug this situation and more frustratingly I haven't been able to find a post with a similar problem from my web searches.
Would appreciate any hints on what might be going on here... or even how you would approach debugging?
Public Sub SaveAttachmentsToDisk(MItem As Outlook.MailItem)
Dim oAttachment As Outlook.Attachment
Dim sSaveFolder As String
sSaveFolder = "C:\RawFiles\"
For Each oAttachment In MItem.Attachments
If UCase(oAttachment.DisplayName) Like "*.XML" Then
oAttachment.SaveAsFile sSaveFolder & oAttachment.DisplayName
MItem.UnRead = False
MItem.Delete
End If
Next
End Sub
OUTLOOK RULE:
I created a rule to move a daily email to a specific folder and run a VBA script to save the table from this email's body.
When the email is received, VBA starts running and grabbing previous email with the same subject and only after does the new email appear in my target folder.
I tried sleep.
Is there any way to first move new email to a target folder then run a script?
Sub ExportOutlookTableToExcel()`
Dim oLookInspector As Inspector
Dim oLookMailitem As MailItem
Dim oLookWordDoc As Word.Document
Dim oLookWordTbl As Word.Table
Dim xlApp As Excel.Application
Dim xlBook As Excel.Workbook
Dim xlWrkSheet As Excel.Worksheet
'Grab Email Item
Set oLookMailitem =Application.ActiveExplorer.CurrentFolder.Items("Apples Sales")
Set oLookInspector = oLookMailitem.GetInspector
Set oLookWordDoc = oLookInspector.WordEditor
Re: I created a rule to move this email to a specific folder and run a VBA script
You are not the first to fall into this trap. Put the move as the last action in the code.
Consider not using "run a script" code in rules. There is ItemAdd for any folder or NewMailEx for the Inbox.
Re: Set oLookMailitem =Application.ActiveExplorer.CurrentFolder.Items("Apples Sales")
The most recent mail with subject "Apples Sales" can be found like this:
Option Explicit ' Consider this mandatory
' Tools | Options | Editor tab
' Require Variable Declaration
' If desperate declare as Variant
Sub mostRecentlyReceivedMail_Subject_DemoOnly()
Dim oLookFolder As Folder
Dim oLookFolderItems As Items
Dim srchSubject As String
Dim i As Long
Dim oLookMailitem As MailItem
Set oLookFolder = ActiveExplorer.CurrentFolder
Set oLookFolderItems = oLookFolder.Items
' sort the collection not the folder
oLookFolderItems.Sort "[ReceivedTime]", True
srchSubject = "Apples Sales"
' This is demonstration code only.
' Without introducing methods to reduce the number of items to look through
' it shows the use of an index rather than subject.
' In this case the required item is supposed to be first in the collection.
For i = 1 To oLookFolderItems.Count
' first verify object in folder is a mailitem
If oLookFolderItems(i).Class = olMail Then
' Index not subject
Set oLookMailitem = oLookFolderItems(i)
If oLookMailitem.subject = srchSubject Then
Debug.Print oLookMailitem.ReceivedTime
oLookMailitem.Display
Exit For
End If
End If
Next
End Sub
Although subject is valid in
Set oLookMailitem =Application.ActiveExplorer.CurrentFolder.Items("Apples Sales")
it probably has little to no practical use.
I creted a rule to move this email to a specific folder and run a vba script to save the table from this new emails body.
There is no need to create a rule and run a VBA script. Instead, to handle incoming emails immediately you need to handle the NewMailEx event which is fired 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. Also you may consider handling the ItemAdd event on the folder where your items are moved. But it has a known disadvantage - the event is not fired if more than sixteen items are moved at the same time. This is a known issue when dealing with OOM.
In the NewMailEx event handler you may get an instance of the incoming email and move it to the required folder programmatically where you could run any other actions.
I am new to VBA and also new here.
Background:
I have just migrated some users from an IMAP server to Exchange. Everything went well except for one user that uses Apple mail app in MacOS. I moved within that app but the sent messages got messed up. The mail app sets the current time as the received time. The mail app and the maiapp in iPhone also uses this timestamp for sorting. So, now I have to find a way to change the received time to the sent time.
I found an answer here:
https://vox.veritas.com/t5/Enterprise-Vault/EV-is-it-possible-to-change-the-date-when-an-email-was-journaled/td-p/590495
I modified it slightly. The error I get is that Item.ReceivedTime is write-protected. How do I get around this?
Sub sent-received()
Set rSession = CreateObject("Redemption.RDOSession")
rSession.MAPIOBJECT = Application.Session.MAPIOBJECT
Set Msg = Application.ActiveExplorer.CurrentFolder
For Each Item In Msg.Items
Item.ReceivedTime = Item.SentOn
Item.Save
Next
End Sub
I designed a macro to send emails with attached files to specific email addresses.
Is it possible to send a reminder email if the recipient never replies to my first email?
Sub MonthlyInterco()
mth = Format(DateAdd("m", -1, Date), "mmmyy")
Call SendFiles("C:\Users\haha\Desktop\interco\")
End Sub
Function SendFiles(fldName As String, Optional FileType As String = "*.*")
Dim fName As String
Dim sAttName As String
Dim olApp As Outlook.Application
Dim olMsg As Outlook.MailItem
Dim olAtt As Outlook.Attachments
Set olApp = Outlook.Application
Set olMsg = olApp.CreateItem(0) ' email
Set olAtt = olMsg.Attachments
' to send all
fName = Dir(fldName)
'to send only certain extensions
'fName = Dir(fldName & FileType)
olAtt.Add fldName & "XYZ " & mth & " INTERCO STATEMENT.pdf"
Debug.Print fName
fName = Dir
' send message
With olMsg
.Subject = mth & " Interco Reconciliation"
.To = "xxx#hotmail.com"
.CC = "yyy#hotmail.com"
.HTMLBody = "Hi all," & "<br /><br /> Attached is " & mth & " interco schedule, kindly reconcile and update us if" & "<br /><br /> 1) Any discrepancies" & "<br />2) All amount tie to your interco bal" & "<br /><br /> Thank you." & "<br /><br /> Best Regards," & "<br /> zzz" & "<br /> "
.Display
End With
End Function
There are two basic approaches you could consider.
The first approach is to use events. I do not necessarily recommend this approach since most people like some experience under their belts before tackling events. You can write a routine and tell Outlook to execute it every time a particular event occurs. For example, there are the send email event and the email received event. You could write a routine that is executed every time you send an email. I would not do too much in that routine since you do not want to slow down your normal work. You could perhaps add the time and receiver email address to the end of a text file. A similar routine could record the time and sender email address when an email is received.
Another routine could be run once a day to process these text files. I would write this routine in Excel VBA so results could be written to worksheets which would help you develop your macros. This macro would have to match emails sent to John Doe against emails received from John Doe and produce a list of emails to which you have not received reply. The receivers of those emails are the people to whom you want to send a chaser email.
If the above approach appeals to you, split it into its components. Do not search for a routine that does everything you want because you will not find it. Do not post a question asking for the routine to be written for you because this site is for programmers to help one another develop; it is not a free coding site.
Look up Outlook events. I do not think the help on Outlook VBA is as good as the help on Excel VBA but it is there. Find examples of the two event routines you require. Look up text files. How do you append to a text file? It is not difficult. How are you going to match entries in the sent and received text files? Perhaps the easiest starting point is to copy the file contents to worksheets which you then sort by email address. Code your macros one step at a time. If you have difficulty with a particular step, come here for help. There is no restriction on the number of questions you can ask providing each shows the code you have tried and explains what is not working as you want/expect.
The second approach is a routine that searches Inbox and Sent Items once a day and extract the information recorded by the event routines. I have already given you a link to a routine that searches Inbox and outputs selected properties of each email to a workbook. This could be the skeleton of the routine you need.
You could search the text bodies of emails you receive for strings of the form: “[CR][LF][CR][LF]On Fri, 4 Nov 2016 at 13:43 zzzz > wrote:[CR][LF][CR][LF]”. Almost all replies to your emails will contain text in this format where zzzz will be your name and xxxx#yyyy will be your email address. This could help matching.
I have tried to give you some ideas. I doubt you can achieve a 100% perfect match between sent and received emails but if you work slowly through the necessary steps you could create a very helpful set of macros.
I get two messages everday. The second message must arrive within 3.5 hours; if not, I have to start figuring out what went wrong with the second process that kept that email from getting sent.
Here's what I'd like to see happen.
Message one arrives
A rule executes and flags the message for follow-up (or anything really) 3.5 hours from that time.
There's a "run script" option in Outlook's Rules Wizard that I would use to trigger the script.
Bonus Points:
3 . When the second email arrives, it clears the follow-up flag from the first message.
Here's what I did:
Sub MyRule(Item As Outlook.MailItem)
MsgBox "Mail one has arrived: " & Item.Subject
Dim newMail As Outlook.MailItem
Set newMail = Outlook.CreateItem(olMailItem)
newMail.To = Item.To
newMail.Subject = "!!!Start looking for issues!!!!"
newMail.Body = "Something might have gone wrong with the process.. You did not receive any closing mail for " + Item.Subject + " received on " + Item.ReceivedTime
newMail.DeferredDeliveryTime = DateAdd("h", 3.5, Now)
newMail.Send
End Sub
This mail sits in your outbox for 3.5 hours and then gets sent.
This works only if you keep outlook running about 3.5 hours after the first mail. Till then when you try to close outlook, it will say that there are items in the outbox which are not sent. You can safely ignore this warning, but make sure that you have Outlook running afterwards.
(some of the code was written and tested in Outlook. but the body and subject part i have typed outside the VB Editor. You might have to resolve minor errors.)
EDIT:: for Bonus points..
Sub MyRuleForMessageTwo(Item As Outlook.MailItem)
Dim myitem As Outlook.MailItem
Set OutboxItems = Application.Session.GetDefaultFolder(olFolderOutbox).Items
Set myitem = OutboxItems.GetFirst
Do While Not (myitem Is Nothing)
If myitem.Subject = "!!!Start looking for issues!!!!" Then
myitem.Delete
Exit Do
End If
Set myitem = OutboxItems.GetNext
Loop
End Sub
You can play around with the matching criteria if you expect more than one message to be sitting in your outbox and you want to delete only one.
First of all, it sounds like you are creating a bizarre Rube Goldberg contraption, but that's going to be your problem, not mine, so have fun!
The way I would do this is to write a simple script that iterates through all messages in the inbox. Set the script to run every five minutes or so.
When it finds the first message of a pair, it records the time that message arrived. If it finds the second message, it checks to make sure that it arrived within 3.5 hours. If it doesn't find the second message, it checks if 3.5 hours have elapsed and warns you if they have.
There is no need to set flags on the first message. This doesn't get you any additional information that your script can't figure out later.