Attach all CSV files in a folder - vba

I'm running a script to automatically send emails with attachments. All attachments will have a .csv extension.
I do not know the name of the files before hand. I am using the Dir statement.
I tried breaking the Dir statement into different strings, but that was not working either.
Dim cAttachment As String
Dim Folder As String
Dim fileCriteria As String
Folder = "C:\Users\____\Desktop\Test Folder"
fileCriteria = ".csv"
cAttachment = Dir(Folder & "\*" & fileCriteria)
I also tried:
Dim cAttachment As String
cAttachment = Dir("C:\Users\___\Desktop\Test Folder\*.csv")
I get
expected end of statement
on the leading parenthesis of my Dir statement.

You can easily achieve your result without having to use the old Dir() Function. To do that you need to use "Scripting.FileSystemObject".
This is the code to discover all files with .csv extension in a specific folder:
Dim oFile As Object
Dim oFSO As Object
Dim oFolder As Object
Dim oFiles As Object
Set oFSO = CreateObject("Scripting.FileSystemObject")
Set oFolder = oFSO.GetFolder("C:\my\Folder\") 'Set this accordingly
Set oFiles = oFolder.Files
'For all files in the folder
For Each oFile In oFiles
If (oFile Like "*.csv") Then
'Add this file to attachments
objMessage.AddAttachment oFile.Path
End If
Next
Hope this helps.

Should be
Folder = "C:\Users\____\Desktop\Test Folder\"
cAttachment = Dir(Folder & "*.csv")`
'// Loop to attch
Do While Len(cAttachment ) > 0
.Attachments.Add Folder & cAttachment
Atmt_File = Dir
Loop
Full Example code
Option Explicit
Private Sub Example()
Dim olMsg As Outlook.MailItem
Dim olRecip As Outlook.Recipient
Dim Atmt_Path As String
Dim olInsp As Outlook.Inspector
Dim wdDoc As Object
Dim rng As Object
Dim Atmt_File As String
'// Attachments Path.
Atmt_Path = "C:\Temp\"
'// Create the message.
Set olMsg = Application.CreateItem(olMailItem)
With olMsg
.Display '// This line must be retained
Atmt_File = Dir(Atmt_Path & "*.csv")
'// Loop to attch
Do While Len(Atmt_File) > 0
.Attachments.Add Atmt_Path & Atmt_File
Atmt_File = Dir
Loop
'// Cancell email if no files to send
If .Attachments.Count = 0 Then
'MsgBox "There are no reports to attach.", vbInformation
.Close 0
.Delete
Else
'// Add the To recipient(s)
Set olRecip = .Recipients.Add("0m3r#email.com")
Set olRecip = .Recipients.Add("0m3r#email.com")
olRecip.Type = olTo
'// Add the CC recipient(s)
Set olRecip = .Recipients.Add("0m3r#email.com")
olRecip.Type = olCC
'// Set the Subject, Body, and Importance of the message.
.Subject = "Reports - " & Format(Now, "Long Date")
.Importance = olImportanceHigh '// High importance
.BodyFormat = olFormatHTML
'// Edit the message body.
Set olInsp = .GetInspector
Set wdDoc = olInsp.WordEditor
'// Set message body (to retain the signature)
Set rng = wdDoc.Range(0, 0)
'// add the text to message body
rng.Text = "Files are Attached, Thank you" & vbCrLf & vbCrLf
'// Resolve each Recipient's name.
For Each olRecip In .Recipients
olRecip.Resolve
If Not olRecip.Resolve Then
olMsg.Display
End If
Next
' .Send '//This line optional
End If
End With
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.

Outlook cannot perform this action on this type of attachment

I am trying to save attachments from an email. I get the error message
Outlook cannot perform this action on this type of attachment
Using Debug.Print outAttachment, it is trying to extract a Picture (Device Independent Bitmap).
I only need the Excel and pdf extracted, but I don't mind extracting the picture if it means the code works.
Public Sub Extract_Attachments_From_Outlook_Msg_Files()
Dim outApp As Object
Dim outEmail As Object
Dim outAttachment As Object
Dim msgFiles As String, sourceFolder As String, saveInFolder As String
Dim fileName As String
Dim FilePath As String
Application.DisplayAlerts = False
msgFiles = Sheets("Instructions").Range("H1") & Sheets("Instructions").Range("H2") & ".msg" 'folder location and filespec of .msg files"
Debug.Print msgFiles
saveInFolder = Sheets("Instructions").Range("H1") 'folder where extracted attachments are saved
Debug.Print saveInFolder
If Right(saveInFolder, 1) <> "\" Then saveInFolder = saveInFolder & "\"
sourceFolder = Left(msgFiles, InStrRev(msgFiles, "\"))
Debug.Print sourceFolder
On Error Resume Next
Set outApp = GetObject(, "Outlook.Application")
If outApp Is Nothing Then
MsgBox "Outlook is not open"
Exit Sub
End If
On Error GoTo 0
fileName = Dir(msgFiles)
While fileName <> vbNullString
Set outEmail = outApp.Session.OpenSharedItem(sourceFolder & fileName)
For Each outAttachment In outEmail.Attachments
outAttachment.SaveAsFile saveInFolder & outAttachment.fileName
Next
fileName = Dir
Wend
End Sub
This is an RTF-formatted message with embedded OLE objects, right?
Outlook Object Model does not allow to do much with attachments of that type (Attachment.Type == olOLE).
If using Redemption is an option (I am its author), its RDOAttachment.SaveAsFile method is smart enough to extract BMP, EMF, PDF, Excel, etc. file data from the storage. Something like the following (off the top of my head) should do the job:
set Session = CreateObject("Redemption.RDOSession")
set outEmail= Session.GetMessageFromMsgFile(sourceFolder & fileName)
For Each outAttachment In outEmail.Attachments
outAttachment.SaveAsFile saveInFolder & outAttachment.fileName
Next
I used:
If att.Type <> olOLE Then
to just skip that object so that I could continue to extract all other attachments.

Saving Outlook Emails as ".msg" not as "File"

I've got this block of code to go through all the emails in my "Today" folder in Outlook, then save all the emails (.msg) to a folder named as the sender name.
Sometimes the files are saving with the file type "file".
How do I fix this to make sure the emails are saved as .msg files?
Sub SaveAttachments()
'https://www.fontstuff.com/outlook/oltut01.htm
'Declare Variables
Dim ns As NameSpace
Dim Inbox As Outlook.MAPIFolder
Dim Item As Object
Dim Atmt As Attachment
Dim Savefolder As String
Dim i As Integer
Set ns = GetNamespace("MAPI")
Set Inbox = ns.GetDefaultFolder(olFolderInbox).Folders("Today")
i = 0
'Stop script if there are no emails
If Inbox.Items.Count = 0 Then
MsgBox "There are no messages in the Inbox.", vbInformation, "Nothing Found"
Exit Sub
End If
'Display the number of emails
MsgBox Inbox.Items.Count, vbInformation, _
"Number of Emails?"
'Go through each email
For Each Item In Inbox.Items
'Create a path for the save folder
Savefolder = "C:\Users\work\Desktop\22_11_18\Test\" & Item.SenderName
'If the email has attachments, then create a folder
If Item.Attachments.Count > 0 Then
MkDir Savefolder
'If the folder already exists, skip to the next statement
On Error Resume Next
'Save the email as a .msg file
Item.SaveAs Savefolder & "\" & Item.Subject & ".msg"
End If
Next Item
End Sub
You can use subject if the characters in the subject are all valid.
Option Explicit
Private Sub SaveMail_ContainingAttachments_ValidSubject()
'Declare Variables
Dim ns As Namespace
Dim targetFolder As Folder
Dim itm As Object
Dim atmt As Attachment
Dim strSaveFolder As String
Dim validSubject As String
Set ns = GetNamespace("MAPI")
Set targetFolder = ns.GetDefaultFolder(olFolderInbox)
Set targetFolder = targetFolder.Folders("Today")
'Stop script if there are no emails
If targetFolder.Items.count = 0 Then
MsgBox "There are no messages in " & targetFolder & ".", vbInformation, "Nothing Found"
Exit Sub
End If
'Display the number of emails
MsgBox targetFolder.Items.count, vbInformation, "Number of Emails?"
'Go through each email
For Each itm In targetFolder.Items
'If the email has attachments, then create a folder
If itm.Attachments.count > 0 Then
'Create a path for the save folder
strSaveFolder = "C:\Users\work\Desktop\22_11_18\Test\" & itm.senderName
' Bypass error if the folder already exists
On Error Resume Next
MkDir strSaveFolder
' Discontinue error bypass as soon as the purpose is served
' Let unknown errors generate then fix them
On Error GoTo 0
' Replace or remove invalid characters
' Possible options "_" or " " or "" ....
validSubject = ReplaceIllegalChar(itm.subject, "_")
If validSubject <> itm.subject Then
Debug.Print itm.subject
Debug.Print validSubject
End If
'Save the email as a .msg file
itm.SaveAs strSaveFolder & "\" & validSubject & ".msg"
End If
Next itm
End Sub
Private Function ReplaceIllegalChar(strInput, strReplace)
Dim RegX As Object
Set RegX = CreateObject("vbscript.regexp")
RegX.Pattern = "[\" & Chr(34) & "\!\#\#\$\%\^\&\*\(\)\=\+\|\[\]\{\}\`\'\;\:\<\>\?\/\,]"
RegX.IgnoreCase = True
RegX.Global = True
' Replace with another string
ReplaceIllegalChar = RegX.Replace(strInput, strReplace)
ExitFunction:
Set RegX = Nothing
End Function

Dwonload attachment from specific sender and open in excel

I am rather new to VBA and was hoping to get some help on a project. To give you some background, I get an email in outlook about every 15 minutes with an excel attachment. I need to open the attachment once the email gets in and view it / compare it to the email that was sent 15 minutes prior. If there is a difference in the emails then I must preform an action. I was hoping to automate at least some of this process. Ideally, I could use a macro to scan my inbox for any new message from a particular sender. If it finds a message it could then check for an attachment and if the attachment is there it would download and open it.
In an ideal world the other thing I could do is compare the prior excel attachment to the current one and ping a message (alert) if it is different.
Any help would be much appreciated. As I said, I am new to VBA but I am trying my best to understand functions.
This should get you started. Assuming you have selected the e-mail in outlook:
Sub check_for_changes()
'Created by Fredrik Östman www.scoc.se
Dim myOlApp As New Outlook.Application
Dim myOlExp As Outlook.Explorer
Dim myOlSel As Outlook.Selection
Set myOlExp = myOlApp.Explorers.Item(1)
Set myOlSel = myOlExp.Selection
Set mymail = myOlSel.Item(1)
Dim myAttachments As Outlook.Attachments
Set myAttachments = mymail.Attachments
Dim Atmt As Attachment
Set Atmt = myAttachments(1)
new_file_name = "C:\tmp\new_received_file.xlsx"
old_file_name = "C:\tmp\old_received_file.xlsx"
FileCopy new_file_name, old_file_name
Atmt.SaveAsFile new_file_name
Dim eApp As Object
Set eApp = CreateObject("Excel.Application")
eApp.Application.Visible = True
Dim new_file As Object
eApp.workbooks.Open new_file_name
Set new_file = eApp.ActiveWorkbook
Dim old_file As Object
eApp.workbooks.Open old_file_name
Set old_file = eApp.ActiveWorkbook
'Find range to compare
start_row = old_file.sheets(1).usedrange.Row
If new_file.sheets(1).usedrange.Row > start_row Then start_row = new_file.sheets(1).usedrange.Row
end_row = old_file.sheets(1).usedrange.Row + old_file.sheets(1).usedrange.Rows.Count
If new_file.sheets(1).usedrange.Rows.Count + new_file.sheets(1).usedrange.Row > end_row Then end_row = new_file.sheets(1).usedrange.Rows.Count + new_file.sheets(1).usedrange.Row
start_col = old_file.sheets(1).usedrange.Column
If new_file.sheets(1).usedrange.Column > start_col Then start_col = new_file.sheets(1).usedrange.Column
end_col = old_file.sheets(1).usedrange.Column + old_file.sheets(1).usedrange.Columns.Count
If new_file.sheets(1).usedrange.Columns.Count + new_file.sheets(1).usedrange.Column > end_row Then end_row = new_file.sheets(1).usedrange.Columns.Count + new_file.sheets(1).usedrange.Column
'Check all cells
something_changed = False
For i = start_row To end_row
For j = start_col To end_col
If new_file.sheets(1).Cells(i, j) <> old_file.sheets(1).Cells(i, j) Then
new_file.sheets(1).Cells(i, j).Interior.ColorIndex = 3 'Mark red
something_changed = True
End If
Next j
Next i
If something_changed Then
new_file.Activate
Else
new_file.Close
old_file.Close
If eApp.workbooks.Count = 0 Then eApp.Quit
MsgBox "No changes"
End If
End Sub
Interesting question, I'll get you started with the outlook part. You'll probably want to split the question between Outlook and Excel.
Here is some code I use to save every attachment I have been sent in Outlook to save space.
Public Sub SaveAttachments()
Dim objOL As Outlook.Application
Dim pobjMsg As Outlook.MailItem 'Object
Dim objSelection As Outlook.Selection
On Error Resume Next
' Instantiate an Outlook Application object.
Set objOL = CreateObject("Outlook.Application")
' Get the collection of selected objects.
Set objSelection = objOL.ActiveExplorer.Selection
For Each pobjMsg In objSelection
SaveAttachments_Parameter pobjMsg
Next
ExitSub:
Set pobjMsg = Nothing
Set objSelection = Nothing
Set objOL = Nothing
MsgBox "Export Complete"
End Sub
Public Sub SaveAttachments_Parameter(objMsg As MailItem)
Dim objAttachments As Outlook.Attachments
Dim i As Long
Dim lngCount As Long
Dim strFile As String
Dim strFolderpath As String
Dim strDeletedFiles As String
' Get the path to your My Documents folder
strFolderpath = "C:\Users\******\Documents\Reports\"
'On Error Resume Next
' Set the Attachment folder.
strFolderpath = strFolderpath & "Outlook Attachments\"
' Get the Attachments collection of the item.
Set objAttachments = objMsg.Attachments
lngCount = objAttachments.Count
If lngCount > 0 Then
' We need to use a count down loop for removing items' from a collection. Otherwise, the loop counter gets' confused and only every other item is removed.
For i = lngCount To 1 Step -1
' Save attachment before deleting from item.
' Get the file name.
strFile = objAttachments.Item(i).FileName
If Right(strFile, 4) = ".png" Or Right(strFile, 4) = ".jpg" Or Right(strFile, 4) = ".gif" Then
GoTo cont
End If
' Combine with the path to the Temp folder.
strFile = strFolderpath & objMsg.SenderName & "." & Format(objMsg.ReceivedTime, "yyyy-MM-dd h-mm-ss") & "." & strFile
' Save the attachment as a file.
objAttachments.Item(i).SaveAsFile strFile
' Delete the attachment - You might not want this part
'objAttachments.Item(i).Delete
'write the save as path to a string to add to the message
'check for html and use html tags in link
If objMsg.BodyFormat = olFormatHTML Then
strDeletedFiles = strDeletedFiles & vbCrLf & "<file://" & Replace(strFile, " ", "%20") & ">"
Else
strDeletedFiles = strDeletedFiles & vbCrLf & "<file://" & Replace(strFile, " ", "%20") & ">"
End If
cont:
Next i
' Adds the filename string to the message body and save it
' Check for HTML body
If objMsg.BodyFormat = olFormatHTML Then
objMsg.Body = "The file(s) were saved to " & strDeletedFiles & vbCrLf & objMsg.Body
Else
objMsg.HTMLBody = "The file(s) were saved to " & strDeletedFiles & vbCrLf & objMsg.HTMLBody
End If
objMsg.Save
End If
ExitSub:
Set objAttachments = Nothing
Set objMsg = Nothing
Set objOL = Nothing
End Sub
The part in the code which says
If Right(strFile, 4) = ".png" Or Right(strFile, 4) = ".jpg" Or Right(strFile, 4) = ".gif" Then
GoTo cont
you could change to something like:
If objMsg.SenderName = "John Smith" Then
GoTo cont
that way it will only save the attachment from that specific sender.
Then, once you have two or more files, you can load the files using another macro in excel and compare the two files, then send you an email if there are any discrepancies.
Hope that gets you started.

Batch file code for a vba program

I have a vba code which works fine, but I want to create the same code as batch file which can do the same thing the vba code is doing.
I have created the code which sends all files in a folder to a specified email address and after sending delete the file.
Can anyone help me in creating the same thing with a batch file which can do the same thing.
Below is the VBA code:
Private Sub Click()
Dim mess_body As String, StrFile As String, StrPath As String
Dim appOutLook As Outlook.Application
Dim MailOutLook As Outlook.MailItem
Set appOutLook = CreateObject("Outlook.Application")
Set MailOutLook = appOutLook.CreateItem(olMailItem)
'~~> Change path here
StrPath = "\Project\New folder\New folder\"
With MailOutLook
.BodyFormat = olFormatRichText
.To = "test#sdm.com"
.Subject = "test"
.HTMLBody = "test"
'~~> *.* for all files
StrFile = Dir(StrPath & "*.*")
Do While Len(StrFile) > 0
.Attachments.Add StrPath & StrFile
StrFile = Dir
Loop
'.DeleteAfterSubmit = True
.Send
End With
Kill "\Project\New folder\New folder\*.*"
MsgBox "Reports have been sent", vbOKOnly
End Sub
U can use cell ("A1") value as folder reference.
Dim objFolder As Object
Set appOutLook = CreateObject("Outlook.Application")
Set MailOutLook = appOutLook.CreateItem(olMailItem)
'~~> Change path here
VAR1 = Range("A1").Value
If VAR1 = False Then MsgBox "Cell is empty"
If VAR1 = False Then Exit Sub
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder(VAR1)
With MailOutLook
.BodyFormat = olFormatRichText
.To = "test#test.com"
.Subject = "test"
.HTMLBody = "test"
'~~> *.* for all files
StrFile = Dir(objFolder & "*.*")
...
'.DeleteAfterSubmit = True
.Send
End With
'delete files
Kill objFolder & "\*.*"