How to automatically save attachment from specific sender? - vba

I would like to automatically save attachments from a specific sender in a predetermined folder.
Public WithEvents objInboxItems As Outlook.Items
Private Sub Application_Startup()
Set objInboxItems = Session.GetDefaultFolder(olFolderInbox).Items
End Sub
Private Sub objInboxItems_ItemAdd(ByVal Item As Object)
Dim objMail As Outlook.MailItem
Dim strSenderAddress As String
Dim strSenderDomain As String
Dim objAttachment As Attachment
Dim strFolderPath As String
Dim strFileName As String
If Item.Class = olMail Then
Set objMail = Item
'Get sender domain
strSenderAddress = objMail.SenderEmailAddress
'strSenderDomain = Right(strSenderAddress, Len(strSenderAddress) - InStr(strSenderAddress, "#"))
'Change to the specific domain as per your needs
If strSenderAddress = "Da.Te#union.de" Then
If objMail.Attachments.Count > 0 Then
For Each objAttachment In objMail.Attachments
'Change the folder path where you want to save attachments
strFolderPath = "U:\Test"
strFileName = objMail.Subject & " " & Chr(45) & " " & objAttachment.FileName
objAttachment.SaveAsFile strFolderPath & strFileName
Next
End If
End If
End If
End Sub
This code is from here, with minor modifications.

How about the following... Remember to restart Outlook
Private WithEvents Items As Outlook.Items
Private Sub Application_Startup()
Dim olNs As Outlook.NameSpace
Dim Inbox As Outlook.MAPIFolder
Set olNs = Application.GetNamespace("MAPI")
Set Inbox = olNs.GetDefaultFolder(olFolderInbox)
Dim Filter As String
Filter = "#SQL=" & Chr(34) & "urn:schemas:httpmail:fromemail" & _
Chr(34) & " Like '%Da.Te#union.de%' And " & _
Chr(34) & "urn:schemas:httpmail:hasattachment" & _
Chr(34) & "=1"
Set Items = Inbox.Items.Restrict(Filter)
End Sub
Private Sub Items_ItemAdd(ByVal Item As Object)
If TypeOf Item Is Outlook.MailItem Then
Dim FilePath As String
FilePath = "C:\Temp\"
Dim AtmtName As String
Dim Atmt As attachment
For Each Atmt In Item.Attachments
AtmtName = FilePath & Atmt.filename
Atmt.SaveAsFile AtmtName
Next
End If
End Sub
Items.ItemAdd Event (Outlook) Occurs when one or more items are added to the specified collection. This event does not run when a large number of items are added to the folder at once. This event is not available in Microsoft Visual Basic Scripting Edition (VBScript).
Items.Restrict method is an alternative to using the Find method or FindNext method to iterate over specific items within a collection. The Find or FindNext methods are faster than filtering if there are a small number of items. The Restrict method is significantly faster if there is a large number of items in the collection, especially if only a few items in a large collection are expected to be found.
Filtering Items Using a String Comparison that DASL filters support includes equivalence, prefix, phrase, and substring matching. Note that when you filter on the Subject property, prefixes such as "RE: " and "FW: " are ignored.

I don't think anything was wrong with your posted code, I too was looking to use that code but not to filter by domain, but specific sender. I tweaked the code a bit for my needs and made it easier to tweak for a new user by moving the 3 fields needing to be modified to the top. I also commented out the part that saved the attachment prefixed with "Subject - Attachmentname" so it saves it purely as "Attachmentname".
My issue was I hadn't enabled Macros in the Trust Center and I had it in a separate Module but it must be under "ThisOutlookSession".
I also added a line to delete the message after saving attachment.
Public WithEvents objInboxItems As Outlook.Items
Private Sub Application_Startup()
Set objInboxItems = Session.GetDefaultFolder(olFolderInbox).Items
End Sub
Private Sub objInboxItems_ItemAdd(ByVal Item As Object)
Dim objMail As Outlook.MailItem
Dim strSenderAddress As String
Dim strSenderDomain As String
Dim objAttachment As Attachment
Dim strFolderPath As String
Dim strFileName As String
Dim strDesiredSender As String
Dim strDesiredDomain As String
strFolderPath = Environ("USERPROFILE") & "\Documents\"
'strDesiredDomain = "gmail.com"
strDesiredSender = "user#gmail.com"
If Item.Class = olMail Then
Set objMail = Item
'Get sender domain
strSenderAddress = objMail.SenderEmailAddress
strSenderDomain = Right(strSenderAddress, Len(strSenderAddress) - InStr(strSenderAddress, "#"))
'Use either strSenderDomain or strSenderAddress Depending on Filter Desired
'If strSenderDomain = strDesiredDomain Then
If strSenderAddress = strDesiredSender Then
If objMail.Attachments.Count > 0 Then
For Each objAttachment In objMail.Attachments
''''Save in format "Subject - Attachmentname"
'strFileName = objMail.Subject & " " & Chr(45) & " " & objAttachment.FileName
'objAttachment.SaveAsFile strFolderPath & strFileName
''''Save in format exactly as attachment name
objAttachment.SaveAsFile strFolderPath & objAttachment.FileName
objMail.Delete 'Delete after saving attachment
Next
End If
End If
End If
End Sub

Related

VB.net - Read .msg file from the shared folder and extract the attachments inside it

I'm completely new to VB and I'm trying to extract the attachment which is saved available inside the .msg file using the below code.
Could someone help me if this is the right approach to do this ?
I'm facing below compiler errors. Could someone help me how to resolve this issue ?
Outlook.Attachment is not defined.
End Sub' must be preceded by a matching 'Sub'
Reference to a non-shared member requires an object reference.
Statement cannot appear within a method body. End of method assumed
Method arguments must be enclosed in parentheses.
Type 'Outlook.MailItem' is not defined.
Sub SaveOlAttachments()
Dim msg As Outlook.MailItem
Dim att As Outlook.Attachment
Dim strFilePath As String
Dim strAttPath As String
Dim strFile As String
strFilePath = "C:\Users\...\Desktop\Test\"
strAttPath = "C:\Users\...\extracted attachment\"
strFile = Dir(strFilePath & "<Doc Name>.msg")
Do While Len(strFile) > 0
msg = Application.CreateItemFromTemplate(strFilePath & strFile)
If msg.Attachments.Count > 0 Then
For Each att In msg.Attachments
att.SaveAsFile strAttPath & att.FileName
Next
End If
strFile = Dir
Loop
End Sub
First of all, check out the file path where you try to find the template:
msg = Application.CreateItemFromTemplate(strFilePath & strFile)
The strFilePath string may include the file name already:
strFile = Dir(strFilePath & "<Doc Name>.msg")
Second, make sure attachments are saved using unique file names:
att.SaveAsFile strAttPath & att.FileName
The FileName string can be the same in different emails. I'd recommend adding IDs or the current time and etc. to the file name to uniquely name attached files on the disk.
Here is the code we use to grab a daily report attachment. I left a few commented statements in case you might need them (we didn't).
Sub Extract_Outlook_Email_Attachments()
On Error GoTo ErrHandler
Dim OutlookApp As Outlook.Application
Dim OutlookNamespace As Namespace
Dim folder As MAPIFolder
Dim OutlookMail As Variant
Dim i As Integer
Dim olNS As Outlook.Namespace
Dim objOwner As Outlook.Recipient
Set OutlookApp = New Outlook.Application
Set OutlookNamespace = OutlookApp.GetNamespace("MAPI")
Dim saveFolder As String
saveFolder = strAttPath ' SAVE THE ATTACHMENT TO
'this bit is added to get a shared email
Set objOwner = OutlookNamespace.CreateRecipient("SHARED FOLDER NAME")
objOwner.Resolve
If objOwner.Resolved Then
Debug.Print "Outlook GB Fulfillment is good."
Set folder = OutlookNamespace.GetSharedDefaultFolder(objOwner, olFolderInbox) 'can use olFolderInbox or olFolderSentMail
End If
'Write mail to spreadsheet - create named range, from and to dates on the spreadsheet
i = 1
For Each OutlookMail In folder.Items
' Debug.Print "SenderEmailAddress: " & OutlookMail.SenderEmailAddress
'If OutlookMail.SenderEmailAddress = "no-reply#OurCompany.com" Then
If OutlookMail.subject = "Daily Report" Then
' If OutlookMail.SenderName = "no-reply#OurCompany.com" And OutlookMail.Subject = "Daily New Subscriber Plan Election Fulfillment" And OutlookMail.Attachments(1) = "NewSubscriberPlanElectionFulfillment_Subscription.xls" Then
Debug.Print "Received: " & OutlookMail.ReceivedTime
Debug.Print "Attach: " & OutlookMail.Attachments(1)
dateformat = Format(OutlookMail.ReceivedTime, "m-d-yy")
Debug.Print dateformat
FName = dateformat & " " & OutlookMail.Attachments(1).fileName
Debug.Print "FName: " & FName
Dim strFileExists As String
strFileExists = Dir(saveFolder & FName)
If strFileExists = "" Then
' MsgBox "The selected file doesn't exist"
Else
' MsgBox "The selected file exists"
Exit Sub
End If
OutlookMail.Attachments(1).SaveAsFile saveFolder & FName
Set outAttachment = Nothing
End If
Next OutlookMail
Set folder = Nothing
Set OutlookNamespace = Nothing
Set OutlookApp = Nothing
ErrHandler:
Debug.Print Err.Description
End Sub
Instead of using CreateItemFromTemplate, you can use Namespace.OpenSharedItem to open an MSG file.
You also need to add Outlook to your VB.Net project references.

How to Search Items with Attachment and keyword in Subject using Filter

I am working on a code which attachment will be download to folder location in context to subject by using a subject filter.
After a long search on the internet, my code is working but the problem here is that I want to put the keyword in the subject filter so that it will download the attachment as the subject keep changing every day
e.g. Sub: training_24357 on one day and training_24359 on the next day.
Also, I want to run my code after every 5 minutes automatically, any help will be much appreciated,
below is my code.
Sub Attachment()
Dim OutOpened As Boolean
Dim App As Outlook.Application
Dim Ns As Outlook.NameSpace
Dim Folder As Outlook.MAPIFolder
Dim Attach As Outlook.Attachment
Dim Item As Object
Dim MailItem As Outlook.MailItem
Dim subject As String
Dim saveFolder As String
Dim dateFormat As String
saveFolder = "D:\Outlook\POS Visit Report"
If Right(saveFolder, 1) <> "\" Then saveFolder = saveFolder & "\"
subject = """*POS Visit*"""
OutOpened = False
On Error Resume Next
Set App = GetObject(, "Outlook.Application")
If Err.Number <> 0 Then
Set App = New Outlook.Application
OutOpened = True
End If
On Error GoTo 0
If App Is Nothing Then
MsgBox "Cannot Start Outlook Mail", vbExclamation
Exit Sub
End If
Set Ns = App.GetNamespace("MAPI")
Set Folder = Ns.GetDefaultFolder(olFolderInbox)
If Not olFolder Is Nothing Then
For Each Item In olFolder.Items
If Item.Class = Outlook.ObjectClass.olMail Then
Set MailItem = Item
If MailItem.subject = subject Then
Debug.Print MailItem.subject
For Each Attach In MailItem.Attachments
dateFormat = Format(Now(), "yyyy-mm-dd H-mm")
Attach.SaveAsFile saveFolder & "(" & dateFormat & ")" & " " & Attach
Next
End If
End If
Next
End If
If OutOpened Then App.Quit
Set App = Nothing
End Sub
To Search for Items with Attachment and by Subject line you can use Items.Restrict Method to filter Items collection containing all the match from the filter
Filter Example: [Attachment & Subject Like '%training%']
Filter = "#SQL=" & Chr(34) & "urn:schemas:httpmail:subject" & _
Chr(34) & " Like '%training%' AND " & _
Chr(34) & "urn:schemas:httpmail:hasattachment" & _
Chr(34) & "=1"
VBA Example https://stackoverflow.com/a/42547062/4539709 Or https://stackoverflow.com/a/42777485/4539709
Now if your running the code from Outlook then you do not need to GetObject, or Set App = New Outlook.Application Just simply Set Ns = Application.GetNamespace("MAPI")
To run your code when Items are added to you Inbox - Try working with Application.Startup Event (Outlook) And Items_ItemAdd Event (Outlook)
Items.ItemAdd Event Occurs when one or more Items are added to the specified collection. This event does not run when a large number of items are added to the folder at once.
Code Example:
Private WithEvents Items As Outlook.Items
Private Sub Application_Startup()
Dim olNs As Outlook.NameSpace
Dim Inbox As Outlook.MAPIFolder
Set olNs = Application.GetNamespace("MAPI")
Set Inbox = olNs.GetDefaultFolder(olFolderInbox)
Set Items = Inbox.Items
End Sub
Private Sub Items_ItemAdd(ByVal Item As Object)
If TypeOf Item Is Outlook.MailItem Then
'// call sub here
End If
End Sub

Automatically export specific emails to text file from Outlook

I am trying to use a VBA script to automatically export all incoming emails with a specific subject to text files that I will then parse with a Python script. The code below works for the most part, but it will randomly skip some of the emails come in.
I haven't found any reason as to why this is, and it doesn't skip emails from the same sender each day, it varies.
We have about 20-30 emails coming in during a 30 minute period or so if that matters. I'd love some help with this.
Private Sub Items_ItemAdd(ByVal Item As Object)
Dim strSubject As String
strSubject = Item.Subject
If TypeOf Item Is Outlook.MailItem And strSubject Like "VVAnalyze Results" Then
SaveMailAsFile Item
End If
End Sub
Private Sub SaveMailAsFile(oMail As Outlook.MailItem)
Dim dtDate As Date
Dim sName As String
Dim sFile As String
Dim sExt As String
sPath = "C:\Users\ltvstatus\Desktop\Backup Reports\"
sExt = ".txt"
sName = oMail.Subject
ReplaceCharsForFileName sName, "_"
dtDate = oMail.ReceivedTime
sName = Format(dtDate, "yyyymmdd", vbUseSystemDayOfWeek, _
vbUseSystem) & Format(dtDate, "-hhnnss", _
vbUseSystemDayOfWeek, vbUseSystem) & "-" & sName & sExt
oMail.SaveAs sPath & sName, olSaveAsTxt
End Sub
Your code looks okay to me so I am not sure if your overwriting your saved emails with new one or your getting to many emails at once while the code is processing one and skipping the other...
I have modified your code to loop in your Inbox and added Function to create new file name if the file already exist...
if you receive 10 email in 1 second, the function will create FileName(1).txt, FileName(2).txt and so on...
I will also advise you to move the emails to subfolder as you SaveAs txt...
Item.Move Subfolder
CODE UPDATED
Option Explicit
Private WithEvents Items As Outlook.Items
Private Sub Application_Startup()
Dim olNs As Outlook.NameSpace
Dim Inbox As Outlook.MAPIFolder
Set olNs = Application.GetNamespace("MAPI")
Set Inbox = olNs.GetDefaultFolder(olFolderInbox)
Set Items = Inbox.Items
End Sub
Private Sub Items_ItemAdd(ByVal Item As Object)
If TypeOf Item Is Outlook.MailItem Then
SaveMailAsFile Item ' call sub
End If
End Sub
Public Sub SaveMailAsFile(ByVal Item As Object)
Dim olNs As Outlook.NameSpace
Dim Inbox As Outlook.MAPIFolder
Dim SubFolder As Outlook.MAPIFolder
Dim Items As Outlook.Items
Dim ItemSubject As String
Dim NewName As String
Dim RevdDate As Date
Dim Path As String
Dim Ext As String
Dim i As Long
Set olNs = Application.GetNamespace("MAPI")
Set Inbox = olNs.GetDefaultFolder(olFolderInbox)
Set Items = Inbox.Items.Restrict("[Subject] = 'VVAnalyze Results'")
Path = Environ("USERPROFILE") & "\Desktop\Backup Reports\"
ItemSubject = Item.Subject
RevdDate = Item.ReceivedTime
Ext = "txt"
For i = Items.Count To 1 Step -1
Set Item = Items.Item(i)
DoEvents
If Item.Class = olMail Then
Debug.Print Item.Subject ' Immediate Window
Set SubFolder = Inbox.Folders("Temp") ' <--- Update Fldr Name
ItemSubject = Format(RevdDate, "YYYYMMDD-HHNNSS") _
& " - " & _
Item.Subject & Ext
ItemSubject = FileNameUnique(Path, ItemSubject, Ext)
Item.SaveAs Path & ItemSubject, olTXT
Item.Move SubFolder
End If
Next
Set olNs = Nothing
Set Inbox = Nothing
Set SubFolder = Nothing
Set Items = Nothing
End Sub
'// Check if the file exists
Private Function FileExists(FullName As String) As Boolean
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
If fso.FileExists(FullName) Then
FileExists = True
Else
FileExists = False
End If
Exit Function
End Function
'// If the same file name exist then add (1)
Private Function FileNameUnique(Path As String, _
FileName As String, _
Ext As String) As String
Dim lngF As Long
Dim lngName As Long
lngF = 1
lngName = Len(FileName) - (Len(Ext) + 1)
FileName = Left(FileName, lngName)
Do While FileExists(Path & FileName & Chr(46) & Ext) = True
FileName = Left(FileName, lngName) & " (" & lngF & ")"
lngF = lngF + 1
Loop
FileNameUnique = FileName & Chr(46) & Ext
Exit Function
End Function

Outlook Macro to move PDF attachments to hard drive

My goal is: on incoming email, move any PDF attachments to a hard drive folder with the date appended to the end of it.
I had a macro running with a rule, but the rule constantly errors and turns off, So I am going to put it in This Outlook Session.
I modified this macro that I found to do what I need, however it is giving me the compile error: Next without For.
Thank you for your assistance on this.
Option Explicit
Private WithEvents olInboxItems As Items
Private Sub Application_Startup()
Dim objNS As NameSpace
Set objNS = Application.Session
' instantiate objects declared WithEvents
Set olInboxItems = objNS.GetDefaultFolder(olFolderInbox).Items
Set objNS = Nothing
End Sub
Private Sub olInboxItems_ItemAdd(ByVal Item As Object)
On Error Resume Next
If Item.Attachments.Count > 0 Then
Dim objAttachments As Outlook.Attachments
Dim lngCount As Long
Dim strFile As String
Dim sFileType As String
Dim i As Long
Dim dtDate As Date
Dim sName As String
Dim objMsg As Outlook.MailItem
Dim lcount As Integer
Dim pre As String
Dim ext As String
Dim strFolderpath As String
Set objAttachments = Item.Attachments
lngCount = objAttachments.Count
For i = lngCount To 1 Step -1
If lngCount > 0 Then
dtDate = objMsg.SentOn
sName = Format(dtDate, "yyyymmdd", vbUseSystemDayOfWeek, vbUseSystem)
' Get the file name.
strFile = sName & objAttachments.Item(i).FileName
If LCase(Right(strFile, 4)) = ".pdf" Then
lcount = InStrRev(strFile, ".") - 1
pre = Left(strFile, lcount)
ext = Right(strFile, Len(strFile) - lcount)
' Combine with the path to make the final path
strFile = strFolderpath & pre & "_" & sName & ext
' Get the path to your My Documents folder
strFolderpath = CreateObject("WScript.Shell").ExpandEnvironmentStrings("%USERPROFILE%")
strFolderpath = strFolderpath & "\1 Inbox\"
' Combine with the path to the folder.
strFile = strFolderpath & strFile
' Save the attachment as a file.
objAttachments.Item(i).SaveAsFile strFile
Next i
End If
End If
End Sub
You don't need rule, try adding this to OutlookSession then restart your Outlook
Private WithEvents Items As Outlook.Items
Private Sub Application_Startup()
Dim olNs As Outlook.NameSpace
Dim Inbox As Outlook.MAPIFolder
Set olNs = Application.GetNamespace("MAPI")
Set Inbox = olNs.GetDefaultFolder(olFolderInbox)
Set Items = Inbox.Items
End Sub
Private Sub Items_ItemAdd(ByVal Item As Object)
If TypeOf Item Is Outlook.MailItem Then
Save_PDF Item
End If
End Sub
Private Sub Save_PDF(ByVal Item As Object)
Dim Atmts As Outlook.Attachments
Dim intCount As Long
Dim sFileName As String
Dim i As Long
Dim sDate As String
Dim Frmt_Date As String
Dim FolderPath As String
If Item.Attachments.Count > 0 Then
Set Atmts = Item.Attachments
intCount = Atmts.Count
For i = intCount To 1 Step -1
If intCount > 0 Then
sDate = Item.SentOn
Frmt_Date = Format(sDate, "yyyymmdd", vbUseSystemDayOfWeek, vbUseSystem)
' Get the file name.
sFileName = Atmts.Item(i).FileName
If LCase(Right(sFileName, 4)) = ".pdf" Then
' Get the path to your My Documents folder
FolderPath = Environ("USERPROFILE") & "\Documents\1 Inbox\"
' Combine with the FolderPath and FileName_DateSentOn
sFileName = FolderPath & Frmt_Date & "_" & sFileName
' Save the attachment as a file.
Atmts.Item(i).SaveAsFile sFileName
End If
End If
Next i
End If
Set Items = Nothing
Set Atmts = Nothing
End Sub

Opening and saving attachments

I have some code that searches the rfin#example.com inbox for messages with a certain subject and then debug prints the subject to the console, I'd like to add code that saves the attachments of those emails flagged by the search. The MSDN documentation was vague on this issue.
The area I'm looking for help with is commented out with '### about 12 lines from the bottom
Sub Search_Inbox()
'This subroutine searchest the RFin Inbox for the prior month's Acting / Additional forms
'Then it saves the .xlsx attachments
Dim objNamespace As Outlook.NameSpace
Dim olShareName As Outlook.Recipient
Dim myDestFolder As Outlook.Folder
Dim objFolder As Outlook.MAPIFolder
Dim DestFolder As Outlook.MAPIFolder
Dim filteredItems As Outlook.Items
Dim itm As Object
Dim Found As Boolean
Dim strFilter As String
Dim mon As String
mon = Format(Date - 30, "mmmm")
Set objNamespace = Application.GetNamespace("MAPI")
Set olShareName = objNamespace.CreateRecipient("rfin#example.com") 'contains secondary address
Set objFolder = objNamespace.GetSharedDefaultFolder(olShareName, olFolderInbox)
Set DestFolder = objNamespace.GetSharedDefaultFolder(olShareName, olFolderToDo)
strFilter = "#SQL=" & Chr(34) & "urn:schemas:httpmail:subject" & Chr(34) & " like '%" & mon & " Acting / Additional Bonus %'"
Set filteredItems = objFolder.Items.Restrict(strFilter)
If filteredItems.Count = 0 Then
Debug.Print "No emails found"
Found = False
Else
Found = True
' this loop displays the list of emails by subject in the debug console and saves the attachments to the specified folder
dim z as integer
z=0
For Each itm In filteredItems
z=z+1
Debug.Print itm.Subject
'### Insert code here to Open the attachments with .xlsx extensions, if any, in each of the emails found, save them as "[Mon] Acting / Additional Bonus (1 to n).xlsx"
Next
End If
'If the subject isn't found:
If Not Found Then
'NoResults.Show
Else
Debug.Print "Found " & filteredItems.Count & " items."
End If
End Sub
Try something like the following:
for each attach in itm.Attachments
if (attach.Type = olByValue) or (attach.Type = olEmbeddeditem) Then
attach.SaveAsFile "c:\temp\" & itm.FileName
End If
next