Outlook VB Script to Create Task From Email - not creating task - vba

I've got the following script which should for all that I can see, work without issue (and in fact at one point yesterday was working - but I must have inadvertently changed something when trying to clean up the code because it's no longer working today).
Perhaps another set of eyes can help me. I have a rule setup to set these emails into their own folder and run the script in Outlook. That works without issue - the issue comes from the script itself.
The subject of the emails that come in that get filtered are generally something like this:
"Ticket: 328157 School: BlahBlah Issues: Problems with flux capacitor"
The idea is that the script will create a task with the appropriate priority level and put it in the appropriate category (and include just the stuff in the subject after 'School"' because the ticket # is not important).
Here is the script:
Sub MakeTaskFromMail(MyMail As Outlook.MailItem)
Dim strID As String
Dim olNS As Outlook.NameSpace
Dim olMail As Outlook.MailItem
Dim objTask As Outlook.TaskItem
'Get Specific Email based on ID
strID = MyMail.EntryID
Set olNS = Application.GetNamespace("MAPI")
Set olMail = olNS.GetItemFromID(strID)
Set objTask = Application.CreateItem(olTaskItem)
'**************************
'*****SET TASK SUBJECT*****
'**************************
Dim sInput As String
Dim sOutput As String
'get the email subject
sInput = olMail.Subject
'get all the text after School: in the subject
sOutput = Mid(sInput, InStr(sInput, "School:") + 8)
Dim priorityUrgentString As String
Dim priorityHighString As String
Dim priorityMediumString As String
Dim priorityLowString As String
'Set Priority Strings to check for to determine category
priorityUrgentString = "Priority: Urgent"
priorityHighString = "Priority: High Priority"
priorityMediumString = "Priority: Medium"
priorityLowString = "Priority: Project"
'check to see if ticket is Urgent
'if urgent - due date is today and alert is set for 8am
If InStr(olMail.Body, priorityUrgentString) <> 0 Then
With objTask
.Subject = sOutput
.DueDate = olMail.SentOn
.Body = olMail.Body
.Categories = "Urgent"
.Importance = olImportanceHigh
.ReminderSet = True
.ReminderTime = objTask.DueDate
End With
'check to see if ticket is High Priority
'if High Priority - due date is today - alert is set for 8am
ElseIf InStr(olMail.Body, priorityHighString) <> 0 Then
With objTask
.Subject = sOutput
.DueDate = olMail.SentOn + 2
.Body = olMail.Body
.Categories = "High"
.Importance = olImportanceHigh
.ReminderSet = True
.ReminderTime = objTask.DueDate + 2
End With
'check to see if its a medium priority
'if medium - due date is set for 7 days, no alert
ElseIf InStr(olMail.Body, priorityMediumString) <> 0 Then
With objTask
.Subject = sOutput
.DueDate = olMail.SentOn + 7
.Body = olMail.Body
.Categories = "Medium"
.Importance = olImportanceNormal
End With
'check to see if its a project priority
'if project - due date is set for 21 days, no alert
ElseIf InStr(olMail.Body, priorityLowString) <> 0 Then
With objTask
.Subject = sOutput
.DueDate = olMail.SentOn + 21
.Body = olMail.Body
.Categories = "Project"
.Importance = olImportanceLow
End With
End If
'Copy Attachments
Call CopyAttachments(olMail, objTask)
'Save Task
objTask.Save
Set objTask = Nothing
Set olMail = Nothing
Set olNS = Nothing
End Sub
Sub CopyAttachments(objSourceItem, objTargetItem)
Set fso = CreateObject("Scripting.FileSystemObject")
Set fldTemp = fso.GetSpecialFolder(2) ' TemporaryFolder
strPath = fldTemp.Path & "\"
For Each objAtt In objSourceItem.Attachments
strFile = strPath & objAtt.FileName
objAtt.SaveAsFile strFile
objTargetItem.Attachments.Add strFile, , , objAtt.DisplayName
fso.DeleteFile strFile
Next
Set fldTemp = Nothing
Set fso = Nothing
End Sub

What I can see without running the script is this:
You will have to save the TaskItem, after setting it (use .Save as the last line within the With)
Also, you will probably have to set the ReminderTime matching the mailitem
.ReminderTime = olMail.SentOn
instead of
.ReminderTime = objTask.DueDate
because it isn't saved yet

Related

Search for sent items with today's date and specific subject

I want when Outlook opens to:
Search sent items with today's date with a specific subject.
If none is found, then send the "Test" email.
If found, display messagebox that says "Email is found".
I have only been able to do #1.
Private Sub Application_Startup()
Dim MItem As MailItem
Set MItem = Application.CreateItem(olMailItem)
MItem.Subject = "Test Alert"
MItem.To = "email#abc.com"
MItem.DeferredDeliveryTime = DateAdd("n", 1, Now) 'n = minute, h=hour
MItem.Send
End Sub
Update:
This is what I've tried. It doesn't seem to be searching the Sent Items folder with the subject.
Public Function is_email_sent()
Dim olApp As Outlook.Application
Dim olNs As Outlook.NameSpace
Dim olFldr As Outlook.Folder
Dim olItms As Outlook.Items
Dim objItem As Outlook.MailItem
On Error Resume Next
Set olApp = New Outlook.Application
Set olNs = olApp.GetNamespace("MAPI")
Set olFldr = olNs.GetDefaultFolder(Outlook.olFolderSentMail)
For Each objItem In olFldr.Items
If objItem.Subject = "Test Alert" And _
objItem.SentOn = Date Then _
MsgBox "Yes. Email found"
Else
MsgBox "No. Email not found"
Exit For
End If
Next objItem
End Function
The main error is misuse of On Error Resume Next. Errors are bypassed, not fixed.
Public Sub is_email_sentFIX()
Dim olFldr As Folder
Dim olItms As Items
Dim objItem As Object
Dim bFound As Boolean
' Not useful here.
' Use for specific purpose to bypass **expected** errors.
'On Error Resume Next
Set olFldr = Session.GetDefaultFolder(olFolderSentMail)
Set olItms = olFldr.Items
olItms.sort "[SentOn]", True
For Each objItem In olItms
If objItem.Class = OlMail Then
Debug.Print objItem.Subject
If objItem.Subject = "Test Alert" Then
Debug.Print objItem.SentOn
Debug.Print Date
If objItem.SentOn > Date Then
MsgBox "Yes. Email found"
bFound = True
Exit For
End If
End If
End If
Next objItem
If bFound = False Then
MsgBox "No. Email not found"
End If
End Sub
If there are an excessive number of items in the Sent folder the "not found" outcome will be slow.
One possible option to the brute force way is to Restrict to the specific item, rather than using If statements.
this is some code ive used;
Sub sendmail10101() 'this is to send the email from contents in a cell
Dim obApp As Object
Dim NewMail As MailItem
Set obApp = Outlook.Application
Set NewMail = obApp.CreateItem(olMailItem)
'You can change the concrete info as per your needs
With NewMail
.Subject = Cells(21, 3).Value
.To = Cells(18, 3).Value
.Body = "Good day" & vbCrLf & "i hope you are keeping well " & vbCrLf & vbCrLf & "please can you assist with the below members infomation;" & vbCrLf & vbCrLf & vbCrLf & Cells(20, 3).Value
'.Attachments.Add ("C:\Attachments\Test File.docx")
.Importance = olImportanceHigh
.Display
End With
Set obApp = Nothing
Set NewMail = Nothing
End Sub
the next part is to search the mail box, which you can also use to search from the first initial cell;
Option Explicit
Public Sub Search_Outlook_Emails()
Dim outApp As Outlook.Application
Dim outNs As Outlook.Namespace
Dim outStartFolder As Outlook.MAPIFolder
Dim foundEmail As Outlook.MailItem
Set outApp = New Outlook.Application
Set outNs = outApp.GetNamespace("MAPI")
'Start at Inbox's parent folder
Set outStartFolder = outNs.GetDefaultFolder(Outlook.olFolderInbox).Parent
'Or start at folder selected by user
'Set outStartFolder = outNs.PickFolder
If Not outStartFolder Is Nothing Then
Set foundEmail = Find_Email_In_Folder(outStartFolder, ThisWorkbook.Sheets("Dashboard").TextBox1.Value)
If Not foundEmail Is Nothing Then
If MsgBox("Email subject: " & foundEmail.Subject & vbNewLine & vbNewLine & _
"Folder: " & foundEmail.Parent.FolderPath & vbNewLine & vbNewLine & _
"Open the email?", vbYesNo, "'" & ThisWorkbook.Sheets("Dashboard").TextBox1.Value & "' found") = vbYes Then
foundEmail.Display
End If
Else
MsgBox "", vbOKOnly, "'" & ThisWorkbook.Sheets("Dashboard").TextBox1.Value & "' not found"
End If
End If
End Sub
Private Function Find_Email_In_Folder(outFolder As Outlook.MAPIFolder, findText As String) As Outlook.MailItem
Dim outItem As Object
Dim outMail As Outlook.MailItem
Dim outSubFolder As Outlook.MAPIFolder
Dim i As Long
Debug.Print outFolder.FolderPath
Set Find_Email_In_Folder = Nothing
'Search emails in this folder
i = 1
While i <= outFolder.Items.Count And Find_Email_In_Folder Is Nothing
Set outItem = outFolder.Items(i)
If outItem.Class = Outlook.OlObjectClass.olMail Then
'Does the findText occur in this email's body text?
Set outMail = outItem
If InStr(1, outMail.Body, findText, vbTextCompare) > 0 Then Set Find_Email_In_Folder = outMail
End If
i = i + 1
Wend
DoEvents
'If not found, search emails in subfolders
i = 1
While i <= outFolder.Folders.Count And Find_Email_In_Folder Is Nothing
Set outSubFolder = outFolder.Folders(i)
'Only check mail item folders
If outSubFolder.DefaultItemType = Outlook.olMailItem Then Set Find_Email_In_Folder = Find_Email_In_Folder(outSubFolder, findText)
i = i + 1
Wend
End Function
the previous code brings us a message box to say if its been found which can be removed but maybe use the message box and an IF statement
such as;
with activeworkbook
if msgbox.value = "yes" then
range("A1:A30") = "COMPLETED" 'ASSUMING THIS IS THE INTIAL TEST RANGE IT WILL CHANGE THE SUBJECT THUS STOPPING THE FIRST MACRO
end if
end with
or if no message box then use something such as IF found then so on...
hope this helps

Checking for attachments before sending the emails using VBA

I have a macro to draft automatic emails based on the recipients in each columns.
However, I'm looking for a code which can if the attachments named in the excel sheet are attached to the email. If there is any attachment missing from that email it should show a msg box with the name of the missing attachment.
SNip of one the sheets attached
Sub Email1()
Dim olApp As Outlook.Application
Set olApp = CreateObject("Outlook.Application")
Dim olMail As Outlook.MailItem
Set olMail = olApp.CreateItem(olMailItem)
Dim FLNM As String
Dim AttchmentName As String
Set AddressList = Sheets("Tracker Summary").Range("Y:Z")
Dim AttchmentName1 As String
Dim path As String
Call FetchFileNames
path = ThisWorkbook.path & "/"
Dim i As Integer
i = 5
With olMail
ActiveSheet.Range("A1").Select
.BodyFormat = olFormatHTML
.Display
.To = ActiveSheet.Cells(2, i).Value
.CC = ActiveSheet.Cells(3, i).Value
.Subject = ActiveSheet.Cells(4, i).Value
.HTMLBody = ActiveSheet.Cells(5, i).Value & .HTMLBody
j = 6
Do Until IsEmpty(Cells(j, i))
On Error Resume Next
FLNM = ActiveSheet.Cells(j, i).Value
AttchmentName1 = Application.WorksheetFunction.VLookup(FLNM, AddressList, 1, True)
If FLNM = AttchmentName1 Then
AttchmentName = Application.WorksheetFunction.VLookup(FLNM, AddressList, 2, True)
.Attachments.Add AttchmentName
End If
j = j + 1
Loop
'.Display
End With
Sheets("Tracker Summary").Range("Y:Z").ClearContents
End Sub
Presuming that AttachmentName is a full file path string, maybe your code could check if the file exists beforehand.
For the sake of simplicity...
If Len(Dir(AttachmentName)) = 0 then msgbox "The File " & AttachmentName & " is missing"
... Just after you set AttachmentName value at AttchmentName = Application.WorksheetFunction.VLookup(FLNM, AddressList, 2, True)
Obviously, same for any other Attachment variables.

Email Multiple Recipients VBA Error

Looking for help with sending emails to a list of people. My code has a simple loop and grabs the value each time through of where to send the email. While testing, the first email will always get sent. After that, the 2nd time through I get error on ".To"
Run-time error - '-2147221238 (8004010a):
The item has been moved or deleted.
This is puzzling to me because the code does accurately grab the next email value?
The emails need to be sent one by one, instead of adding the recipients to a list of bcc. Is this possible with VBA? Thanks in advance!
Sub TestingAgain()
'Setting up the Excel variables.
Dim outApp As Object
Dim outMailItem As Object
Dim iCounter As Integer
Dim sDest As String
Dim sName As String
'Create the Outlook application and the empty email.
Set outApp = CreateObject("Outlook.Application")
Set outMailItem = outApp.CreateItem(0)
With outMailItem
sDest = ""
For i = 2 To WorksheetFunction.CountA(Columns(1))
If i <> "" Then
'Grab first name and email
sDest = Cells(i, 5).Value
sName = Cells(i, 1).Value
'Send each email
.To = sDest
.Subject = "FYI"
.htmlbody = "Some stuff"
.Send
Else
MsgBox ("Error")
End If
Next i
End With
'Clean up the Outlook application.
Set outMailItem = Nothing
Set outApp = Nothing
End Sub
When you send the e-mail, the mailItem instance is done and not available anymore. Refactor your code like :
Sub TestingAgain()
'Setting up the Excel variables.
Dim outApp As Object
Dim outMailItem As Object
Dim iCounter As Integer
Dim sDest As String
Dim sName As String
'Create the Outlook application and the empty email.
Set outApp = CreateObject("Outlook.Application")
sDest = ""
For i = 2 To WorksheetFunction.CountA(Columns(1))
If i <> "" Then
'/ Create the mail item instance.
Set outMailItem = outApp.CreateItem(0)
With outMailItem
'Grab first name and email
sDest = Cells(i, 5).Value
sName = Cells(i, 1).Value
'Send each email
.To = sDest
.Subject = "FYI"
.htmlbody = "Some stuff"
.send
'/ Once sent, mail item is no more available.
End With
Else
MsgBox ("Error")
End If
Next
'Clean up the Outlook application.
Set outMailItem = Nothing
Set outApp = Nothing
End Sub

How do I loop through a specific folder in outlook

What would be the VBA code for looping through a specific folder in outlook 2010 that is NOT the default inbox nor a subfolder of the inbox?
Dim ns As Outlook.NameSpace
Dim folder As MAPIFolder
Set ns = Session.Application.GetNamespace("MAPI")
Set folder = Please help me :-)
Thank you for any hint and help, greetings Ionic
Change
Set ns = Session.Application.GetNamespace("MAPI")
To
Set ns = Session.Application.GetNamespace("MAPI").PickFolder
This will prompt you to select the folder.
Here's a full routine that I wrote some time ago that may be of assistance, bear in mind this was written so that it could be run from Excel but should provide you with the syntax that you need:
Sub GetMail()
'// This sub is designed to be used with a blank worksheet. It will create the header
'// fields as required, and continue to populate the email data below the relevant header.
'// Declare required variables
'-------------------------------------------------------------
Dim olApp As Object
Dim olFolder As Object
Dim olMailItem As Object
Dim strTo As String
Dim strFrom As String
Dim dateSent As Variant
Dim dateReceived As Variant
Dim strSubject As String
Dim strBody As String
Dim loopControl As Variant
Dim mailCount As Long
Dim totalItems As Long
'-------------------------------------------------------------
'//Turn off screen updating
Application.ScreenUpdating = False
'//Setup headers for information
Range("A1:F1").Value = Array("To", "From", "Subject", "Body", "Sent (from Sender)", "Received (by Recipient)")
'//Format columns E and F to
Columns("E:F").EntireColumn.NumberFormat = "DD/MM/YYYY HH:MM:SS"
'//Create instance of Outlook
Set olApp = CreateObject("Outlook.Application")
'//Select folder to extract mail from
Set olFolder = olApp.GetNamespace("MAPI").PickFolder
'//Get count of mail items
totalItems = olFolder.items.Count
mailCount = 0
'//Loop through mail items in folder
For Each loopControl In olFolder.items
'//If loopControl is a mail item then continue
If TypeName(loopControl) = "MailItem" Then
'//Increase mailCount
mailCount = mailCount + 1
'//Inform user of item count in status bar
Application.StatusBar = "Reading email no. " & mailCount & " of " & totalItems
'//Get mail item
Set olMailItem = loopControl
'//Get Details
With olMailItem
strTo = .To
'//If strTo begins with "=" then place an apostrophe in front to denote text format
If Left(strTo, 1) = "=" Then strTo = "'" & strTo
strFrom = .Sender
'//If sender displays name only, show name followed by email address e.g.(Bloggs, Joe < j.bloggs#mail.com >)
If InStr(1, strFrom, "#") < 1 Then strFrom = strFrom & " - < " & .SenderEmailAddress & " >"
dateSent = .SentOn
dateReceived = .ReceivedTime
strSubject = .Subject
strBody = .Body
End With
'//Place information into spreadsheet
'//import information starting from last blank row in column A
With Range("A" & Rows.Count).End(xlUp).Offset(1, 0)
.Value = strTo
.Offset(0, 1).Value = strFrom
.Offset(0, 2).Value = strSubject
'//Check for previous replies by looking for "From:" in the body text
'//Check for the word "From:"
If InStr(0, strBody, "From:") > 0 Then
'//If exists, copy start of email body, up to the position of "From:"
.Offset(0, 3).Value = Mid(strBody, 1, InStr(1, strBody, "From:") - 1)
Else
'//If doesn't exist, copy entire mail body
.Offset(0, 3).Value = strBody
End If
.Offset(0, 4).Value = dateSent
.Offset(0, 5).Value = dateReceived
End With
'//Release item from memory
Set olMailItem = Nothing
End If
'//Next Item
Next loopControl
'//Release items from memory
Set olFolder = Nothing
Set olApp = Nothing
'//Resume screen updating
Application.ScreenUpdating = True
'//reset status bar
Application.StatusBar = False
'//Inform user that code has finished
MsgBox mailCount & " messages copied successfully.", vbInformation, "Complete"
End Sub
Okay, I've found it myself.
Set folder = ns.GetDefaultFolder(olFolderInbox).Parent.Folders(NAME OF THE FOLDER)
Than you for your help guys !

Preserving html format in creating tasks from email

I have a little script that converts an email into a Task in my outlook.
My main frustration is that it won't preserve the html format, and deals with embedded images as attachments. I was wondering if anyone could help. I know it is possible as I've copied the body of an email directly across to the body of a task manually and it is preserved fine.
Sub ConvertSelectedMailtoTask()
Dim objApp As Outlook.Application
Dim objTask As Outlook.TaskItem
Dim objMail As Outlook.MailItem
Set objTask = Application.CreateItem(olTaskItem)
Set objApp = Application
If TypeName(objApp.ActiveWindow) = "Explorer" Then
For Each objMail In Application.ActiveExplorer.Selection
If Left(objMail.Subject, 3) = "RE:" Or Left(objMail.Subject, 3) = "FW:" Then
subj = Right(objMail.Subject, Len(objMail.Subject) - 4)
Else
subj = objMail.Subject
End If
With objTask
.Subject = subj
.Importance = objMail.Importance
.StartDate = objMail.ReceivedTime
.Body = objMail.Body
.DueDate = Date + 3
If objMail.Attachments.Count > 0 Then
CopyAttachments objMail, objTask
End If
.ReminderSet = True
.ReminderTime = Date + 2.5
.Sensitivity = olPrivate
.Save
End With
Next
ElseIf TypeName(objApp.ActiveWindow) = "Inspector" Then
Set objMail = objApp.ActiveInspector.CurrentItem
If Left(objMail.Subject, 3) = "RE:" Or Left(objMail.Subject, 3) = "FW:" Then
subj = Right(objMail.Subject, Len(objMail.Subject) - 4)
Else
subj = objMail.Subject
End If
With objTask
.Subject = subj
.Importance = objMail.Importance
.StartDate = objMail.ReceivedTime
.Body = objMail.Body
.DueDate = Date + 3
If objMail.Attachments.Count > 0 Then
CopyAttachments objMail, objTask
End If
.ReminderSet = True
.ReminderTime = Date + 2.5
.Sensitivity = olPrivate
.Save
End With
End If
Set objTask = Nothing
Set objMail = Nothing
Set objApp = Nothing
End Sub
And here is the script for the attachments
Sub CopyAttachments(objSourceItem, objTargetItem)
Set fso = CreateObject("Scripting.FileSystemObject")
Set fldTemp = fso.GetSpecialFolder(2) ' TemporaryFolder
strPath = fldTemp.Path & "\"
For Each objAtt In objSourceItem.Attachments
strFile = strPath & objAtt.FileName
objAtt.SaveAsFile strFile
objTargetItem.Attachments.Add strFile, , , objAtt.DisplayName
fso.DeleteFile strFile
Next
Set fldTemp = Nothing
Set fso = Nothing
End Sub
Update:
I found a bit of code that uses a word document to preserve the formatting:
Sub CopyFullBody(sourceItem As Object, targetItem As Object)
Dim objDoc As Word.Document
Dim objSel As Word.Selection
Dim objDoc2 As Word.Document
Dim objSel2 As Word.Selection
On Error Resume Next
' get a Word.Selection from the source item
Set objDoc = sourceItem.GetInspector.WordEditor
If Not objDoc Is Nothing Then
Set objSel = objDoc.Windows(1).Selection
objSel.WholeStory
objSel.Copy
Set objDoc2 = targetItem.GetInspector.WordEditor
If Not objDoc2 Is Nothing Then
Set objSel2 = objDoc2.Windows(1).Selection
objSel2.PasteAndFormat wdPasteDefault
Else
MsgBox "Could not get Word.Document for " & _
targetItem.Subject
End If
Else
MsgBox "Could not get Word.Document for " & _
sourceItem.Subject
End If
Set objDoc = Nothing
Set objSel = Nothing
Set objDoc2 = Nothing
Set objSel2 = Nothing
End Sub
This doesn't seem like it would be the only solution hence updating my own post instead of answering my question as this seems a bit long winded (using another application just to give me formatting, when I can copy and paste text manually just fine all in Outlook). If anyone has any other thoughts on this/defining attachment types please carry on answering!
in the line
.Body = objMail.Body
you only ask fot the non-formatted Body. Try instead:
.Body = objMail.htmlBody
and something completely different: I just put reminders onto the emails themselves, so I have no need to create extra Tasks at all...
Keep in mind that Outlook tasks, appointments and tasks work with RTF, not HTML. hence TaskItem, ContactItem and AppointmentItem objects only expose the RtfBody property, but not HTMLBody (like MailItem does).
You will need to either convert HTML to RTF (you can try the Word Object Model for that) or use Redemption (I am its author): unlike Outlook Object Model, it exposes the RDOTaskItem.HTMLBody property and dynamically converts HTML to the native (for tasks) RTF when that property is set.