Only run if email has attachment - vba

I want the below code to run when a specific subject appears in an email.
Also to only run if that email has an attachment.
Outlook ignores the attachment part of the rule, and tries to run the code even if the attachment is not there (it seems to only care about the subject).
How do I incorporate a check for attachment in the code?
Public Sub SaveAttachmentsThenOpen(MItem As Outlook.MailItem)
Dim oMail As Variant
Dim oReply As Outlook.MailItem
Dim oItems As Outlook.Items
Dim Msg As Outlook.MailItem
Dim oAttachment As Outlook.Attachment
Dim StrBody As String
Dim oRep As MailItem
Dim sSaveFolder As String
Dim Att As String
Dim Attname As String
Dim sht As Object
Dim Rng As Range
Dim s As String
Dim myAttachments As Outlook.Attachments
Dim XLApp As Object
Dim XlWK As Object
Dim strPaste As Variant
Set oApp = New Outlook.Application
Set oNs = oApp.GetNamespace("MAPI")
Set XLApp = CreateObject("Excel.Application")
With XLApp
.Visible = True
.ScreenUpdating = True
.Workbooks.Open ("C:\Directory\data.xlsx")
.Workbooks.Open ("C:\Directory\WB.xlsb")
End With
Dim strText As String
strText = ".xls"
sSaveFolder = "C:\Directory\TPS_Reports\"
For Each oAttachment In MItem.Attachments
If InStr(1, oAttachment.FileName, strText) > 0 Then
oAttachment.SaveAsFile sSaveFolder & oAttachment.FileName
Attname = oAttachment.FileName
Att = sSaveFolder & oAttachment.FileName
Exit For
End If
Next oAttachment
Set oAttachment = Nothing
XLApp.Workbooks.Open (Att)
XLApp.Visible = True
XLApp.Run ("WB.XLSB!MacroName")
Set sht = XLApp.Workbooks(Attname).ActiveSheet
Set Rng = sht.UsedRange
s = "<table border=1 bordercolor=black cellspacing=0>"
For rw = Rng.Row To Rng.Rows.Count
s = s & "<tr>"
For col = Rng.Column To Rng.Columns.Count
s = s & "<td>" & sht.Cells(rw, col) & "</td>"
Next
s = s & "</tr>"
Next
s = s & "</table>"
Set oRep = MItem.ReplyAll
With oRep
StrBody = "Hello"
.HTMLBody = s
.Send
End With
With XLApp
.DisplayAlerts = False
End With
XLApp.Workbooks(Attname).Save
XLApp.Quit
With XLApp
.DisplayAlerts = True
End With
End Sub

Try waiting for the mail to be in the inbox before checking for the attachment.
Code for the ThisOutlookSession module
Restart Outlook or run Application_Startup manually.
Private WithEvents myItems As Items
Private Sub Application_Startup()
Dim myInbox As folder
Set myInbox = Session.GetDefaultFolder(olFolderInbox)
Set myItems = myInbox.Items
End Sub
Private Sub myItems_ItemAdd(ByVal Item As Object)
If TypeOf Item Is mailItem Then
If Item.Attachments.Count > 0 Then
SaveAttachmentsThenOpen Item
End If
End If
End Sub
Private Sub test()
myItems_ItemAdd ActiveInspector.currentItem
End Sub

Related

Create Outlook email routing rule based on ticket ID using VBA

I tried to create email routing rule with below scenario.
Incoming email will be located at Inbox/Active folder. Subject of the email will contain the ticket ID and content
Once new email coming to Active subfolder, Outlook will get the email subject and create the subfolder with format "ticket ID - content" eg: "123123 - issue with outlook"
Then a rule will be created to route this incoming email with ticket ID to the subfolder that I just created
Below is my code but it did not work. Only subfolder is created as expected. Please help me to review if any idea. Thanks
Option Explicit
Private WithEvents inboxItems As Outlook.Items
Private Sub Application_Startup()
Dim olapp As Outlook.Application
Dim olnamespace As Outlook.NameSpace
Set olapp = Outlook.Application
Set olnamespace = olapp.GetNamespace("MAPI")
Set inboxItems = olnamespace.GetDefaultFolder(olFolderInbox).Folders("Filter").Items
End Sub
Private Sub inboxItems_ItemAdd(ByVal Item As Object)
On Error GoTo ErrorHandler
Dim olapp As Outlook.Application
Dim olnamespace As Outlook.NameSpace
Dim olActivefolder As Folder
Dim ticketnumber As String
Dim rightsubject As String
Dim leftsubject As String
Dim extsubject As String
Dim colRules As Outlook.Rules
Dim oRule As Outlook.Rule
Dim colRuleActions As Outlook.RuleActions
Dim oMoveRuleAction As Outlook.MoveOrCopyRuleAction
Dim oFromCondition As Outlook.ToOrFromRuleCondition
Dim oExceptSubject As Outlook.TextRuleCondition
Dim oInbox As Outlook.Folder
Dim oMoveTarget As Outlook.Folder
Set olapp = Outlook.Application
Set olnamespace = olapp.GetNamespace("MAPI")
Set olActivefolder = olnamespace.GetDefaultFolder(olFolderInbox).Folders("Active")
If TypeName(Item) = "MailItem" Then
Debug.Print "triggered"
ticketnumber = Item.Subject
rightsubject = Right(ticketnumber, 16)
leftsubject = Left(ticketnumber, 60)
olActivefolder.Folders.Add (rightsubject & " - " & leftsubject)
End If
Set oInbox = Application.Session.GetDefaultFolder(olFolderInbox).Folders("Active")
Set oMoveTarget = oInbox.Folders(rightsubject & " - " & leftsubject)
Set colRules = Application.Session.DefaultStore.GetRules()
Set oRule = colRules.Create(rightsubject, olRuleReceive)
Set oFromCondition = oRule.Conditions.Subject
With oFromCondition
.Enabled = True
.Text = rightsubject
End With
Set oMoveRuleAction = oRule.Actions.MoveToFolder
With oMoveRuleAction
.Enabled = True
.Folder = oMoveTarget
End With
colRules.Save
ExitNewItem:
Exit Sub
ErrorHandler:
MsgBox Err.Number & " - " & Err.Description
Resume ExitNewItem
End Sub
The subject condition should look like this:
'Dim oFromCondition As Outlook.ToOrFromRuleCondition
'Set oFromCondition = oRule.Conditions.subject
'With oFromCondition
' .Enabled = True
' .Text = rightSubject
'End With
Dim oSubjectCondition As TextRuleCondition
Set oSubjectCondition = oRule.Conditions.subject
With oSubjectCondition
.Enabled = True
.Text = Array(rightSubject)
End With
There is likely no need for rules.
Private Sub inboxItems_ItemAdd_Test()
inboxItems_ItemAdd ActiveInspector.CurrentItem
End Sub
Private Sub inboxItems_ItemAdd(ByVal Item As Object)
' Folder created for first mail
' No folder created for subsequent mail
Dim oInbox As folder
Dim oActivefolder As folder
Dim oMoveTarget As folder
Dim oFolder As folder
Dim ticketNumber As String
Set oInbox = Session.GetDefaultFolder(olFolderInbox)
Set oActivefolder = oInbox.Folders("Active")
If TypeName(Item) = "MailItem" Then
Debug.Print "triggered"
' For testing
ticketNumber = "123123"
For Each oFolder In oActivefolder.Folders
If oFolder.Name = ticketNumber Then
Set oMoveTarget = oActivefolder.Folders(ticketNumber)
Debug.Print " Folder exists: " & oMoveTarget.Name
Exit For
End If
Next
If oMoveTarget Is Nothing Then
Set oMoveTarget = oActivefolder.Folders.Add(ticketNumber)
Debug.Print " Folder added: " & oMoveTarget.Name
End If
Item.Move oMoveTarget
End If
Debug.Print "Done."
End Sub

Issue Outlook PDF download by received link

I used this code by Simon Li, but for some reason it always gives me a connection problem once i start outlook.
I wanted to create a PDF downloader for certain emails we receive and actually it worked for quite a while, but now the script doesnt trigger anymore:
Private WithEvents Items As Outlook.Items
Private Sub Application_Startup()
Dim olApp As Outlook.Application
Set olApp = Outlook.Application
Set Items = GetNS(olApp).GetDefaultFolder(olFolderInbox).Folders("Tagblätter").Items
End Sub
Private Sub Items_ItemAdd(ByVal item As Object)
On Error GoTo ErrorHandler
'Variablen definieren
Dim olMsg As MailItem
Dim i As Integer
Dim olApp As Outlook.Application
Dim olNS As Outlook.NameSpace
Dim olFolder As Outlook.Folder
Dim olItems As Outlook.Items
Dim olMailItem As Outlook.MailItem
Dim linkLoc As Integer
Dim link As String
Dim Pfad As String
Dim WinHttpReq As Object
Dim oStream As Object
Dim Datum As Date
Dim strDatum As String
Dim CountMail As Long
'Speicherpfad angeben
Pfad = "L:\Newsletter\"
'Inhalt von Tagblätter checken
On Error Resume Next
Set olApp = New Outlook.Application
Set olNS = olApp.GetNamespace("MAPI")
Set olFolder = olNS.GetDefaultFolder(olFolderInbox).Folders("Tagblätter")
Set olItems = olFolder.Items
'Link aus Body extrahieren
For i = CountMail To 1 Step -1
Set olMsg = olItems.item(i)
linkLoc = InStr(1, olMsg.Body, "PDF herunterladen")
link = Mid(olMsg.Body, linkLoc + 8)
link = Split(link, "<")(1)
link = Split(link, ">")(0)
'Aktuelles Datum für Ordner beziehen
Datum = olMsg.ReceivedTime
strDatum = Datum
strDatum = Split(strDatum, " ")(0)
strDatum = Split(strDatum, ".")(2) + Split(strDatum, ".")(1) + Split(strDatum, ".")(0)
Pfad = Pfad + strDatum
'Link öffnen
Set WinHttpReq = CreateObject("WinHttp.WinHttpRequest.5.1")
WinHttpReq.Open "GET", link, False
WinHttpReq.Send
'Check ob Adresse erreichbar
If WinHttpReq.Status = 200 Then
'Ordner mit aktuallem Datum erstellen
Set FSO = CreateObject("Scripting.FileSystemObject")
FSO.CreateFolder Pfad
'PDF abspeichern
Set oStream = CreateObject("ADODB.Stream")
oStream.Open
oStream.Type = 1
oStream.Write WinHttpReq.ResponseBody
oStream.SaveToFile (Pfad + "\" + olMsg.Sender + "-" + olMsg.Subject + ".pdf")
oStream.Close
End If
'E-Mail löschen
olMsg.Delete
Next i
'Variablen leeren
Set olMsg = Nothing
Pfad = ""
ProgramExit:
Exit Sub
ErrorHandler:
MsgBox Err.Number & " - " & Err.Description
Resume ProgramExit
End Sub
Function GetNS(ByRef app As Outlook.Application) As Outlook.NameSpace
Set GetNS = app.GetNamespace("MAPI")
End Function
Does anyone have an idea? Thank you in advance!
Ok i got the answer.
For i = CountMail To 1 Step -1
Somehow i forgot to actually Count the Mails:
CountMail = olNS.GetDefaultFolder(olFolderInbox).Folders("Tagblätter").Items.Count
And second issue was here:
Datum = olMsg.ReceivedTime
Changed it to:
Datum = olItems.item(i).ReceivedTime
Well, anyway maybe someone has a need for this code. Or there might be smth to code better?
For us it works quite nice, cos the emails we receive always got the same format and linked text.
Cheers

How to call code where “Argument not optional”?

I want to make a rule for Outlook to move mail.
I have VBA code that works.
How do I call that code as script.
Part of the code:
Option Explicit
Sub CheckAttachments(olItem As MailItem)
Const strPath As String = "C:\Users\PC2\Documents\Temp_attachs\"
Const strFindText As String = "Completed"
Dim strFilename As String
Dim olAttach As Attachment
Dim xlApp As Object
Dim xlWB As Object
Dim xlSheet As Object
Dim bXStarted As Boolean
Dim bFound As Boolean
Dim myNameSpace As Outlook.NameSpace
Dim myInbox As Outlook.Folder
Dim myDestFolder As Outlook.Folder
Set myNameSpace = Application.GetNamespace("MAPI")
Set myInbox = myNameSpace.GetDefaultFolder(olFolderInbox)
Set myDestFolder = myInbox.Folders("Subfolder1")
If olItem.Attachments.Count > 0 Then
For Each olAttach In olItem.Attachments
If Right(LCase(olAttach.FileName), 4) = "xlsx" Then
strFilename = strPath & Format(olItem.ReceivedTime, "yyyymmdd-HHMMSS") & _
Chr(32) & olAttach.FileName
olAttach.SaveAsFile strFilename
On Error Resume Next
Set xlApp = GetObject(, "Excel.Application")
If Err <> 0 Then
Application.StatusBar = "Please wait while Excel source is opened ... "
Set xlApp = CreateObject("Excel.Application")
bXStarted = True
End If
On Error GoTo 0
'Open the workbook to read the data
Set xlWB = xlApp.workbooks.Open(strFilename)
Set xlSheet = xlWB.sheets("Sheet1")
If FindValue(strFindText, xlSheet) Then
olItem.Move myDestFolder
'MsgBox "Value found in " & strFilename
bFound = True
End If
xlWB.Close 0
If bXStarted Then xlApp.Quit
If Not bFound Then Kill strFilename
'Exit For
End If
Next olAttach
End If
End Sub
There is a Function also for FindValue.
I tried:
Sub callmacro(Item as Outlook.MailItem)
call ChcekAttachments
End SUB
I get compiler error message:
Argument not optional
Try this. You need to pass argument in Check sub - (olItem As MailItem)
Sub callmacro(Item as Outlook.MailItem)
call CheckAttachments Item
End sub

Issue with Class Module Outlook VBA

I am new to VBA and am trying to insert a class module to save an email that arrives to a sub-folder in the inbox called "My Folder" to a location on a sharedrive. I have the below code and have tried sending emails to test but it is not working and cannot figure out why. Any help would be greatly appreciated!
Private WithEvents InboxItems As Outlook.Items
Sub Application_Startup()
Dim xNameSpace As Outlook.NameSpace
Set xNameSpace = Outlook.Application.Session
Set InboxItems = xNameSpace.GetDefaultFolder(olFolderInbox)
Set InboxItems = olFolder.Folders("My Folder")
End Sub
Private Sub InboxItems_ItemAdd(ByVal objItem As Object)
Dim FSO
Dim xMailItem As Outlook.MailItem
Dim xFilePath As String
Dim xRegEx
Dim xFileName As String
On Error Resume Next
xFilePath = CreateObject("WScript.Shell").SpecialFolders(16)
xFilePath = xFilePath & "File Path on Share Drive will be entered here"
Set FSO = CreateObject("Scripting.FileSystemObject")
If FSO.FolderExists(xFilePath) = False Then
FSO.CreateFolder (xFilePath)
End If
Set xRegEx = CreateObject("vbscript.regexp")
xRegEx.Global = True
xRegEx.IgnoreCase = False
xRegEx.Pattern = "\||\/|\<|\>|""|:|\*|\\|\?"
If objItem.Class = olMail Then
Set xMailItem = objItem
xFileName = xRegEx.Replace(xMailItem.Subject, "")
xMailItem.SaveAs xFilePath & "\" & xFileName & ".msg", olMSG
End If
Exit Sub
End Sub
There were a few issues with the code that I saw. I have this working, make sure you add this to the ThisOutlookSession object in the VBA IDE.
Private WithEvents InboxItems As Outlook.Items
Private Sub Application_Startup()
Dim outlookApp As Outlook.Application: Set outlookApp = Outlook.Application
Dim objectNS As Outlook.NameSpace: Set objectNS = outlookApp.GetNamespace("MAPI")
Set InboxItems = objectNS.GetDefaultFolder(olFolderInbox).Items
End Sub
Private Sub InboxItems_ItemAdd(ByVal Item As Object)
Dim FolderPath As String: FolderPath = "YOUR PATH HERE"
Dim FileName As String
Static FSO As Object
If FSO Is Nothing Then Set FSO = CreateObject("Scripting.FileSystemObject")
If FSO.FolderExists(FolderPath) = False Then FSO.CreateFolder FolderPath
With CreateObject("vbscript.regexp")
.Global = True
.IgnoreCase = False
.Pattern = "\||\/|\<|\>|""|:|\*|\\|\?"
If Item.Class = olMail Then
FileName = .Replace(Item.Subject, vbNullString)
Item.SaveAs FolderPath & FileName & ".msg", olMSG
End If
End With
End Sub

Outlook 2010 VBA Macro Saving Attachments

I have the following code in ThisOutlookSession to save PDF attachments from emails when the emails go into a certain sub-folder in Outlook.
I thought I wasn't using the Initialize Handler correctly, but I have tried to change it around to no avail.
Public WithEvents myOlItem As Outlook.Items
Dim myOlApp As New Outlook.Application
Public Sub Initialize_handler()
Set myOlItem = myOlApp.GetNamespace("MAPI").GetDefaultFolder(olFolderInbox).Folders("WAM").Folders("UNPROCESSED").Items
End Sub
Private Sub myOlItem_ItemAdd(ByVal Item As Object)
Dim myOlMItem As Outlook.MailItem
Dim myOlAtts As Outlook.Attachments
Set myOlAtts = myOlMItem.Attachments
Call CallMyProcedure(Item)
End Sub
Sub CallMyProcedure()
Dim itms As Outlook.Items
Dim Itm As Object
' loop through default Inbox items
Set itms = myOlMItem 'Session.GetDefaultFolder(olFolderInbox).Folders("WAM").Folders("UNPROCESSED").Items
For Each Itm In itms
If TypeName(Itm) = "MailItem" Then
' your code is called here
savePDFtoDisk Itm
End If
Next Itm
Set objEmail = Nothing
End Sub
Sub savePDFtoDisk(Itm As Outlook.MailItem)
Dim dateFormat 'Dateiname mit Datum.
Dim objAtt As Outlook.Attachment
Dim saveFolder As String
dateFormat = Format(Now, "mm_yyyy")
saveFolder = "\\marnv006\#marnv006\Bm\Master Scheduling\PC 2.2.11 Work Authorizing Memorandum (WAMs)\WAMS added to WAM Track\"
For Each objAtt In Itm.Attachments
If (InStr(1, objAtt.DisplayName, "WAM", vbTextCompare) > 0) Then
If LCase(Right(objAtt.FileName, 4)) = ".pdf" Then
objAtt.SaveAsFile saveFolder & objAtt.DisplayName
Set objAtt = Nothing
End If 'Nach PDF filtern.
End If
Next
End Sub
Replace the line Sub Initialize_handler() with Sub Application_Startup()
Or use this format
Sub Application_Startup()
Initialize_handler
End Sub
Edit 2015 11 16
The code is too convoluted. Redetermining the affected items than failing to pass them along.
Option Explicit
' In ThisOutlookSession
Private WithEvents myOlItem As Items
' Not needed if in Outlook
'Dim myOlApp As New Outlook.Application
'Public Sub Initialize_handler()
Private Sub application_Startup()
Dim myNS As Namespace
Dim myFolder As Folder
Set myNS = GetNamespace("MAPI")
Set myFolder = myNS.GetDefaultFolder(olFolderInbox)
Set myFolder = myFolder.Folders("WAM")
Set myFolder = myFolder.Folders("UNPROCESSED")
Set myOlItem = myFolder.Items
ExitRoutine:
Set myNS = Nothing
Set myFolder = Nothing
End Sub
' No need to redetermine items, ItemAdd already knows.
' Note itm to match the savePDFtoDisk code, not item.
Private Sub myOlItem_ItemAdd(ByVal Itm As Object)
'Sub savePDFtoDisk(Itm As Outlook.mailItem)
Dim dateFormat 'Dateiname mit Datum.
Dim objAtt As Outlook.attachment
Dim saveFolder As String
dateFormat = Format(Now, "mm_yyyy")
saveFolder = "\\marnv006\#marnv006\Bm\Master Scheduling\PC 2.2.11 Work Authorizing Memorandum (WAMs)\WAMS added to WAM Track\"
For Each objAtt In Itm.Attachments
If (InStr(1, objAtt.DisplayName, "WAM", vbTextCompare) > 0) Then
If LCase(Right(objAtt.Filename, 4)) = ".pdf" Then
objAtt.SaveAsFile saveFolder & objAtt.DisplayName
Set objAtt = Nothing
End If 'Nach PDF filtern.
End If
Next
End Sub