I've found in the internet and modified a bit a piece of code:
Public WithEvents objMails As Outlook.Items
Private Sub Application_Startup()
Const pierwszy = "pierwszy#gmail.com"
Const drugi = "drugi#gmail.com"
Dim OutAcc As Account
Debug.Print "Startup"
For Each OutAcc In Outlook.Application.Session.Accounts
If (OutAcc.DisplayName = pierwszy) Then
Set objMails = OutAcc.DeliveryStore.GetDefaultFolder(olFolderInbox).Items
Exit For
End If
If (OutAcc.DisplayName = drugi) Then
Set objMails = OutAcc.DeliveryStore.GetDefaultFolder(olFolderInbox).Items
Exit For
End If
Next
End Sub
Private Sub objMails_ItemAdd(ByVal Item As Object)
Dim objMail As Outlook.MailItem
Dim strExcelFile As String
Dim objExcelApp As Excel.Application
Dim objExcelWorkBook As Excel.Workbook
Dim objExcelWorkSheet As Excel.Worksheet
Dim nNextEmptyRow As Integer
Dim strColumnB As String
Dim strColumnC As String
Dim strColumnD As String
Dim strColumnE As String
If Item.Class = olMail Then
Set objMail = Item
End If
'Specify the Excel file which you want to auto export the email list
'You can change it as per your case
strExcelFile = "C:\Users\karol\Documents\test.xlsx"
'Get Access to the Excel file
On Error Resume Next
Set objExcelApp = GetObject(, "Excel.Application")
If Error <> 0 Then
Set objExcelApp = CreateObject("Excel.Application")
End If
Set objExcelWorkBook = objExcelApp.Workbooks.Open(strExcelFile)
Set objExcelWorkSheet = objExcelWorkBook.Sheets("Arkusz1")
'Get the next empty row in the Excel worksheet
nNextEmptyRow = objExcelWorkSheet.Range("B" & objExcelWorkSheet.Rows.Count).End(xlUp).Row + 1
'Specify the corresponding values in the different columns
strColumnB = objMail.SenderName
strColumnC = objMail.SenderEmailAddress
strColumnD = objMail.Subject
strColumnE = objMail.ReceivedTime
strColumnF = objMail.Body
strColumnG = objMail.To
'Add the vaules into the columns
objExcelWorkSheet.Range("A" & nNextEmptyRow) = nNextEmptyRow - 1
objExcelWorkSheet.Range("B" & nNextEmptyRow) = strColumnB
objExcelWorkSheet.Range("C" & nNextEmptyRow) = strColumnC
objExcelWorkSheet.Range("D" & nNextEmptyRow) = strColumnD
objExcelWorkSheet.Range("E" & nNextEmptyRow) = strColumnE
objExcelWorkSheet.Range("F" & nNextEmptyRow) = strColumnF
objExcelWorkSheet.Range("G" & nNextEmptyRow) = strColumnG
'Fit the columns from A to E
objExcelWorkSheet.Columns("A:G").AutoFit
'Save the changes and close the Excel file
objExcelWorkBook.Close SaveChanges:=True
End Sub
This code works fine, when in Outlook application I am logged in at one mailbox (one e-mail). I've faced a problem when I am trying to automatically export emails from two mailboxes (two accounts with different email addresses on which I am logged in to the Outlook application) - look at the picture:
https://ibb.co/mXWZJsw
I tried to solve this problem by using If statements in the Application_Startup () procedure (as seen in the code above). This approach, unfortunately, does not work. I also noticed that, for example, when the first email arrives at the account "pierwszy#gmail.com", then until the application is closed, emails will be exported to Excel only from this account "pierwszy#gmail.com" and not exported from the account "drugi#gmail.com". However, when the first e-mail arrives at the account "drugi#gmail.com", then emails will be exported from the seccond e-mail "drugi#gmail.com" until application is closed.
Let me preface this by saying - not sure how rules work for multiple accounts. You may need to create the rule for BOTH accounts but they can both reference the same script.
I've updated your code to be a public Sub vs Private Sub and placed it in a module so that it can be referenced by the rules engine.
Now, once we have the code in place (scripts run by Rules engine typically inherently pass the email as a MailItem to the sub and ByVal was causing issues with recognizing the script as one to be run from a MailItem so i updated it to Item as MailItem).
We next create a new rule using the rules engine. If you see this simplistic interface, click on Advanced Options. That will allow us to apply to rule to all emails. In the advanced options window, do not check any box for Which conditions do you want to check? simply click Next. It will confirm you want to add this rule for ALL EMAILS which we do.
After selecting run a script we can click on a script to indicate which script we want to run. I set it to the exportToExcel script in Module(Project)1
Click Finish and test it out.
Sub exportToExcel(item As MailItem)
Dim objMail As Outlook.MailItem
Dim strExcelFile As String
Dim objExcelApp As Excel.Application
Dim objExcelWorkBook As Excel.Workbook
Dim objExcelWorkSheet As Excel.Worksheet
Dim nNextEmptyRow As Integer
Dim strColumnB As String
Dim strColumnC As String
Dim strColumnD As String
Dim strColumnE As String
If item.Class = olMail Then
Set objMail = item
End If
'Specify the Excel file which you want to auto export the email list
'You can change it as per your case
strExcelFile = "C:\Users\karol\Documents\test.xlsx"
'Get Access to the Excel file
On Error Resume Next
Set objExcelApp = GetObject(, "Excel.Application")
If Error <> 0 Then
Set objExcelApp = CreateObject("Excel.Application")
End If
Set objExcelWorkBook = objExcelApp.Workbooks.Open(strExcelFile)
Set objExcelWorkSheet = objExcelWorkBook.Sheets("Arkusz1")
'Get the next empty row in the Excel worksheet
nNextEmptyRow = objExcelWorkSheet.Range("B" & objExcelWorkSheet.Rows.count).End(xlUp).Row + 1
'Specify the corresponding values in the different columns
strColumnB = objMail.SenderName
strColumnC = objMail.SenderEmailAddress
strColumnD = objMail.Subject
strColumnE = objMail.ReceivedTime
strColumnF = objMail.Body
strColumnG = objMail.To
'Add the vaules into the columns
objExcelWorkSheet.Range("A" & nNextEmptyRow) = nNextEmptyRow - 1
objExcelWorkSheet.Range("B" & nNextEmptyRow) = strColumnB
objExcelWorkSheet.Range("C" & nNextEmptyRow) = strColumnC
objExcelWorkSheet.Range("D" & nNextEmptyRow) = strColumnD
objExcelWorkSheet.Range("E" & nNextEmptyRow) = strColumnE
objExcelWorkSheet.Range("F" & nNextEmptyRow) = strColumnF
objExcelWorkSheet.Range("G" & nNextEmptyRow) = strColumnG
'Fit the columns from A to E
objExcelWorkSheet.Columns("A:G").AutoFit
'Save the changes and close the Excel file
objExcelWorkBook.Close SaveChanges:=True
End Sub
You can monitor multiple folders with ItemAdd.
Option Explicit
Public WithEvents objMailspierwszy As Items
Public WithEvents objMailsdrugi As Items
Private Sub Application_Startup()
Const pierwszy = "pierwszy#somewhere.com"
Const drugi = "drugi#somewhere.com"
Dim OutAcc As Account
For Each OutAcc In Session.Accounts
Debug.Print "OutAcc.DisplayName: " & OutAcc.DisplayName
Debug.Print "OutAcc.DeliveryStore: " & OutAcc.DeliveryStore
If OutAcc.DisplayName = pierwszy Then
Debug.Print "OutAcc.DisplayName: " & OutAcc.DisplayName
Set objMailspierwszy = OutAcc.DeliveryStore.GetDefaultFolder(olFolderInbox).Items
Debug.Print "Listener on " & objMailspierwszy.Parent & " of DeliveryStore " & OutAcc.DeliveryStore
End If
If OutAcc.DisplayName = drugi Then
Debug.Print "OutAcc.DisplayName: " & OutAcc.DisplayName
Set objMailsdrugi = OutAcc.DeliveryStore.GetDefaultFolder(olFolderInbox).Items
Debug.Print "Listener on " & objMailspierwszy.Parent & " of DeliveryStore " & OutAcc.DeliveryStore
End If
Next
End Sub
Private Sub objMailspierwszy_ItemAdd(ByVal Item As Object)
'...
End Sub
Private Sub objMailsdrug_ItemAdd(ByVal Item As Object)
'...
End Sub
Related
I've been trying to export details about my incoming emails to an Excel spreadsheet. The code works as it should except for returning display names for the recipients in the "To" and "CC" fields.
I tried several variations.
I'm using the below code that I found online:
Public WithEvents objMails As Outlook.Items
Private Sub Application_Startup()
Set objMails = Outlook.Application.Session.GetDefaultFolder(olFolderInbox).Items
End Sub
Private Sub objMails_ItemAdd(ByVal Item As Object)
Dim objMail As Outlook.MailItem
Dim Recipient As Outlook.Recipient
Dim strExcelFile As String
Dim objExcelApp As Excel.Application
Dim objExcelWorkBook As Excel.Workbook
Dim objExcelWorkSheet As Excel.Worksheet
Dim nNextEmptyRow As Integer
Dim strColumnB As String
Dim strColumnC As String
Dim strColumnD As String
Dim strColumnE As String
Dim strColumnF As String
Dim strColumnG As String
If Item.Class = olMail Then
Set objMail = Item
End If
'Specify the Excel file which you want to auto export the email list
'You can change it as per your case
strExcelFile = "C:\Users\yakir.machluf\Documents\Outlook automation test.xlsx"
'Get Access to the Excel file
On Error Resume Next
Set objExcelApp = GetObject(, "Excel.Application")
If Error <> 0 Then
Set objExcelApp = CreateObject("Excel.Application")
End If
Set objExcelWorkBook = objExcelApp.Workbooks.Open(strExcelFile)
Set objExcelWorkSheet = objExcelWorkBook.Sheets("Sheet1")
'Get the next empty row in the Excel worksheet
nNextEmptyRow = objExcelWorkSheet.Range("B" & objExcelWorkSheet.Rows.Count).End(xlUp).Row + 1
'Specify the corresponding values in the different columns
strColumnB = objMail.SenderName
strColumnC = objMail.SenderEmailAddress
strColumnD = objMail.Subject
strColumnE = objMail.ReceivedTime
strColumnF = objMail.To
strColumnG = objMail.CC
'Add the vaules into the columns
objExcelWorkSheet.Range("A" & nNextEmptyRow) = nNextEmptyRow - 1
objExcelWorkSheet.Range("B" & nNextEmptyRow) = strColumnB
objExcelWorkSheet.Range("C" & nNextEmptyRow) = strColumnC
objExcelWorkSheet.Range("D" & nNextEmptyRow) = strColumnD
objExcelWorkSheet.Range("E" & nNextEmptyRow) = strColumnE
objExcelWorkSheet.Range("F" & nNextEmptyRow) = strColumnF
objExcelWorkSheet.Range("G" & nNextEmptyRow) = strColumnG
'Fit the columns from A to G
objExcelWorkSheet.Columns("A:G").AutoFit
'Save the changes and close the Excel file
objExcelWorkBook.Close SaveChanges:=True
End Sub
.Recipient has an .Address property.
Recipient.Address property (Outlook) https://learn.microsoft.com/en-us/office/vba/api/outlook.recipient.address
Option Explicit
Public WithEvents objMails As Items
Private Sub Application_Startup()
Set objMails = Session.GetDefaultFolder(olFolderInbox).Items
End Sub
Private Sub objMails_ItemAdd(ByVal Item As Object)
Dim objMail As MailItem
Dim i As Long
Dim recipAddresses As String
If Item.Class = olMail Then
Set objMail = Item
For i = 1 To objMail.Recipients.Count
recipAddresses = recipAddresses & objMail.Recipients(i).Address & " "
Next
Debug.Print Trim(recipAddresses)
End If
End Sub
Private Sub test_objMails_ItemAdd()
objMails_ItemAdd ActiveInspector.CurrentItem
End Sub
Code in detail:
Option Explicit
Private Sub objMails_ItemAdd(ByVal Item As Object)
Dim objMail As MailItem
Dim recip As Recipient
Dim recipAddressesTo As String
Dim recipAddressesCC As String
Dim i As Long
Dim strExcelFile As String
' Early binding - Set reference to Excel XX.X Object Library
Dim objExcelApp As Excel.Application
Dim objExcelWorkBook As Excel.Workbook
Dim objExcelWorkSheet As Excel.Worksheet
Dim nNextEmptyRow As Long
If Item.Class = olMail Then
Set objMail = Item
'Specify the Excel file
strExcelFile = "C:\Users\yakir.machluf\Documents\Outlook automation test.xlsx"
'Get the Excel file
' Bypass normal error handling
On Error Resume Next ' To be used for a specific purpose
Set objExcelApp = GetObject(, "Excel.Application")
' ?
Debug.Print " Error: " & Error
'If Error <> 0 Then
Debug.Print " Err..: " & Err
If Err <> 0 Then
Set objExcelApp = CreateObject("Excel.Application")
End If
' Return to normal error handling
On Error GoTo 0 ' Consider mandatory after On Error Resume Next
Set objExcelWorkBook = objExcelApp.Workbooks.Open(strExcelFile)
Set objExcelWorkSheet = objExcelWorkBook.Sheets("Sheet1")
With objExcelWorkSheet
'Get the next empty row in the Excel worksheet
nNextEmptyRow = .Range("B" & .Rows.Count).End(xlUp).Row + 1
'Specify the corresponding values in the different columns
.Range("A" & nNextEmptyRow) = nNextEmptyRow - 1
.Range("B" & nNextEmptyRow) = objMail.senderName
.Range("C" & nNextEmptyRow) = objMail.SenderEmailAddress
.Range("D" & nNextEmptyRow) = objMail.Subject
.Range("E" & nNextEmptyRow) = objMail.ReceivedTime
For i = 1 To objMail.Recipients.Count
Set recip = objMail.Recipients(i)
If recip.Type = olTo Then
recipAddressesTo = recipAddressesTo & recip.Address & " "
ElseIf recip.Type = olCC Then
recipAddressesCC = recipAddressesCC & recip.Address & " "
End If
Next
' Trim the space character at the end
objExcelWorkSheet.Range("F" & nNextEmptyRow) = Trim(recipAddressesTo)
objExcelWorkSheet.Range("G" & nNextEmptyRow) = Trim(recipAddressesCC)
'Fit the columns from A to G
objExcelWorkSheet.Columns("A:G").AutoFit
End With
'Save the changes and close the Excel file
objExcelWorkBook.Close SaveChanges:=True
End If
End Sub
Thanks to niton, I ended up tweaking the code and using the following.
The new problem I'm facing is trying to get the exchange addresses to appear as regular email addresses.
Any hints?
Public WithEvents objMails As Outlook.Items
Private Sub Application_Startup()
Set objMails = Outlook.Application.Session.GetDefaultFolder(olFolderInbox).Items
End Sub
Private Sub objMails_ItemAdd(ByVal Item As Object)
Dim objMail As Outlook.MailItem
Dim Recipient As Outlook.Recipient
Dim recipAddressesTo As String
Dim recipAddressesCC As String
Dim i As Long
Dim strExcelFile As String
Dim objExcelApp As Excel.Application
Dim objExcelWorkBook As Excel.Workbook
Dim objExcelWorkSheet As Excel.Worksheet
Dim nNextEmptyRow As Integer
Dim strColumnB As String
Dim strColumnC As String
Dim strColumnD As String
Dim strColumnE As String
Dim strColumnF As String
Dim strColumnG As String
If Item.Class = olMail Then
Set objMail = Item
End If
'Specify the Excel file which you want to auto export the email list
'You can change it as per your case
strExcelFile = "C:\Users\yakir.machluf\Documents\Outlook automation test.xlsx"
'Get Access to the Excel file
On Error Resume Next
Set objExcelApp = GetObject(, "Excel.Application")
If Error <> 0 Then
Set objExcelApp = CreateObject("Excel.Application")
End If
Set objExcelWorkBook = objExcelApp.Workbooks.Open(strExcelFile)
Set objExcelWorkSheet = objExcelWorkBook.Sheets("Sheet1")
'Get the next empty row in the Excel worksheet
nNextEmptyRow = objExcelWorkSheet.Range("B" & objExcelWorkSheet.Rows.Count).End(xlUp).Row + 1
'Add the vaules into the columns
objExcelWorkSheet.Range("A" & nNextEmptyRow) = nNextEmptyRow - 1
objExcelWorkSheet.Range("B" & nNextEmptyRow) = objMail.SenderName
objExcelWorkSheet.Range("C" & nNextEmptyRow) = objMail.SenderEmailAddress
objExcelWorkSheet.Range("D" & nNextEmptyRow) = objMail.Subject
objExcelWorkSheet.Range("E" & nNextEmptyRow) = objMail.ReceivedTime
For i = 1 To objMail.Recipients.Count
Set recip = objMail.Recipients(i)
If recip.Type = olTo Then
recipAddressesTo = recipAddressesTo & recip.Address & " "
ElseIf recip.Type = olCC Then
recipAddressesCC = recipAddressesCC & recip.Address & " "
End If
Next
' Trim the space character at the end
objExcelWorkSheet.Range("F" & nNextEmptyRow) = Trim(recipAddressesTo)
objExcelWorkSheet.Range("G" & nNextEmptyRow) = Trim(recipAddressesCC)
'Fit the columns from A to G
objExcelWorkSheet.Columns("A:G").AutoFit
'Save the changes and close the Excel file
objExcelWorkBook.Close SaveChanges:=True
End Sub
I have created a fully functional outlook macro, that downloads Outlook attachments to OneDrive specified folder.
So the macro would update the file name with the email domain and month/year
e.g.
from original attachment name "Invoice_GBR_Z-GRX_2019_07.pdf"
it becomes "comfone.com_08-2019___Invoice_GBR_Z-GRX_2019_07.pdf" after executing the macro.
However, I would like the macro to also have the ability to compare against a static Excel table called Table.xls on my desktop (2 columns where column A contain the email domain name, and column B containing its respective company code), wherein if the Excel cell contains "comfone.com", then its corresponding company code say 0001 would then be appended to the file name
So the file name gets updated to
"0001_comfone.com_08-2019___Invoice_GBR_Z-GRX_2019_07.pdf"
I'm struggling quite a fair bit not knowing how to reference to an Excel table from my Outlook vba.
Public Sub SaveAttachments()
Dim objOL As Outlook.Application
Dim objMsg As Outlook.MailItem 'Object
Dim objAttachments As Outlook.Attachments
Dim objSelection As Outlook.Selection
Dim i As Long
Dim lngCount As Long
Dim strFile As String
Dim strFolderpath As String
Dim strDeletedFiles As String
Dim saveName As String
Dim userName As String
Dim sndrEmailAdd As String
Dim sndrEmailRight As String
Dim sndrEmailPreDot As String
' Get the path to your OneDrive folder.
userName = CreateObject("WScript.Network").userName
Debug.Print userName
'strFolderpath = "C:\Users\" & VBA.Environ$("USERNAME") & "\OneDrive - SAP
SE"
strFolderpath = "C:\Users\" & userName & "\OneDrive - SAP SE"
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
' Set the Test folder, change "Test" to any folder name in your OneDrive
strFolderpath = strFolderpath & "\Downloaded Invoices\"
' Check each selected item for attachments. If attachments exist,
' save them to the strFolderPath folder and strip them from the item.
For Each objMsg In objSelection
' This code only strips attachments from mail items.
' If objMsg.class=olMail Then
' Get the Attachments collection of the item.
Set objAttachments = objMsg.Attachments
lngCount = objAttachments.Count
strDeletedFiles = ""
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
'Extract text, after # and before dot, from the email address.
sndrEmailAdd = objMsg.SenderEmailAddress
Debug.Print sndrEmailAdd
'Debug.Print " position of # sign: " & InStr(sndrEmailAdd, "#")
'Debug.Print " number of characters right of # sign: " &
Len(sndrEmailAdd) - InStr(sndrEmailAdd, "#")
'sndrEmailRight = Right(sndrEmailAdd, Len(sndrEmailAdd) -
InStr(sndrEmailAdd, "#"))
sndrEmailRight = Right(sndrEmailAdd, Len(sndrEmailAdd) -
InStr(sndrEmailAdd, "#"))
Debug.Print " text after # sign: " & sndrEmailRight
Debug.Print " position of the (first) . period in the remaining text:
" & InStr(sndrEmailRight, ".")
'sndrEmailPreDot = Left(sndrEmailRight, InStr(sndrEmailRight, ".") -
1)
' Save attachment before deleting from item.
' Get the file name.
strFile = sndrEmailRight & "_" & Format(DateAdd("m", -1,
objMsg.ReceivedTime), "mm-yyyy") & "___" &
objAttachments.item(i).FileName
' Combine with the path to the Temp folder.
saveName = strFolderpath & strFile
' Save the attachment as a file.
objAttachments.item(i).SaveAsFile saveName
' Delete the attachment.
'objAttachments.item(i).Delete
Next i
objMsg.Save
End If
Next
ExitSub:
Set objAttachments = Nothing
Set objMsg = Nothing
Set objSelection = Nothing
Set objOL = Nothing
End Sub
See example on how to call Excel from Outlook
https://stackoverflow.com/a/41801050/4539709
I have updated your code, make sure to Reference to Microsoft Excel xx.x Object Library and update your one-drive folder path
Your code example
Option Explicit
Public Sub SaveAttachments()
Dim Atmts As Outlook.Attachments
Dim i As Long
Dim lngCount As Long
Dim strFile As String
Dim strDeletedFiles As String
Dim saveName As String
Dim userName As String
Dim sndrEmailAdd As String
Dim sndrEmailRight As String
Dim sndrEmailPreDot As String
Dim strFolderpath As String
strFolderpath = "C:\Temp\"
' Get the collection of selected objects.
Dim objSelection As Outlook.Selection
Set objSelection = Application.ActiveExplorer.Selection
Dim xlApp As Excel.Application
Set xlApp = New Excel.Application
Dim Book As Workbook
Set Book = xlApp.Workbooks.Open("C:\Temp\Book1.xlsx")
Dim xlStarted As Boolean
xlStarted = True
Dim Sht As Excel.Worksheet
Set Sht = Book.Sheets("Sheet1")
Dim Rng As Range
' Check each selected item for attachments. If attachments exist,
' save them to the strFolderPath folder and strip them from the item.
Dim objMsg As Outlook.MailItem 'Object
For Each objMsg In objSelection
' This code only strips attachments from mail items.
' If objMsg.class=olMail Then
' Get the Attachments collection of the item.
Set Atmts = objMsg.Attachments
lngCount = Atmts.Count
Debug.Print lngCount
strDeletedFiles = ""
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
'Extract text, after # and before dot, from the email address.
sndrEmailAdd = objMsg.SenderEmailAddress
Debug.Print sndrEmailAdd
sndrEmailRight = Right(sndrEmailAdd, Len( _
sndrEmailAdd) - InStr( _
sndrEmailAdd, "#"))
Debug.Print sndrEmailRight
sndrEmailPreDot = Left(sndrEmailRight, _
InStr(sndrEmailRight, ".") - 1)
Debug.Print sndrEmailPreDot
For Each Rng In Sht.Range("A1", Sht.Range("A100").End(xlUp))
If (Rng.Value) = sndrEmailRight Then
sndrEmailPreDot = Rng.Offset(0, 1).Value & "_" & sndrEmailPreDot
Debug.Print sndrEmailPreDot
End If
Next
' Save attachment before deleting from item.
' Get the file name.
strFile = sndrEmailPreDot & "_" & _
Format(DateAdd("m", -1, objMsg.ReceivedTime _
), "mm-yyyy") & "___" & Atmts.Item(i).FileName
Debug.Print strFile
' Combine with the path to the Temp folder.
saveName = strFolderpath & strFile
Debug.Print saveName
' Save the attachment as a file.
Atmts.Item(i).SaveAsFile saveName
' Delete the attachment.
'Atmts.item(i).Delete
Next i
objMsg.Save
End If
Next
' Close & SaveChanges
Book.Close SaveChanges:=True
If xlStarted Then
xlApp.Quit
End If
Set xlApp = Nothing
Set Book = Nothing
Set Sht = Nothing
Set Rng = Nothing
Set Atmts = Nothing
Set objMsg = Nothing
Set objSelection = Nothing
End Sub
I'm setting up an automatic solution to export incoming mails from Outlook into an Excel file.
I found several solutions online but I get a compile error.
I'm using Outlook 2016 and Windows 8.1.
I thought it's a reference problem, but I found the FM20.DLL and it's still not working.
The error I get:
Compile error: User-defined type not defined
at line Dim objExcelApp As Excel.Application
Public WithEvents objMails As Outlook.Items
Private Sub Application_Startup()
Set objMails =
Outlook.Application.Session.GetDefaultFolder(olFolderInbox).Items
End Sub
Private Sub objMails_ItemAdd(ByVal Item As Object)
Dim objMail As Outlook.MailItem
Dim strExcelFile As String
Dim objExcelApp As Excel.Application
Dim objExcelWorkBook As Excel.Workbook
Dim objExcelWorkSheet As Excel.Worksheet
Dim nNextEmptyRow As Integer
Dim strColumnB As String
Dim strColumnC As String
Dim strColumnD As String
Dim strColumnE As String
If Item.Class = olMail Then
Set objMail = Item
End If
'Specify the Excel file which you want to auto export the email list
'You can change it as per your case
strExcelFile = "H:\SF_Mail\Emails.xlsx"
'Get Access to the Excel file
On Error Resume Next
Set objExcelApp = GetObject(, "Excel.Application")
If Error <> 0 Then
Set objExcelApp = CreateObject("Excel.Application")
End If
Set objExcelWorkBook = objExcelApp.Workbooks.Open(strExcelFile)
Set objExcelWorkSheet = objExcelWorkBook.Sheets("Sheet1")
'Get the next empty row in the Excel worksheet
nNextEmptyRow = objExcelWorkSheet.Range("B" & objExcelWorkSheet.Rows.Count).End(xlUp).Row + 1
'Specify the corresponding values in the different columns
strColumnB = objMail.SenderName
strColumnC = objMail.SenderEmailAddress
strColumnD = objMail.Subject
strColumnE = objMail.ReceivedTime
'Add the vaules into the columns
objExcelWorkSheet.Range("A" & nNextEmptyRow) = nNextEmptyRow - 1
objExcelWorkSheet.Range("B" & nNextEmptyRow) = strColumnB
objExcelWorkSheet.Range("C" & nNextEmptyRow) = strColumnC
objExcelWorkSheet.Range("D" & nNextEmptyRow) = strColumnD
objExcelWorkSheet.Range("E" & nNextEmptyRow) = strColumnE
'Fit the columns from A to E
objExcelWorkSheet.Columns("A:E").AutoFit
'Save the changes and close the Excel file
objExcelWorkBook.Close SaveChanges:=True
End Sub
References
It's an error that appears when a reference is missing.
Try to add in Tools-> References:
Microsoft Excel [Your Version] Object Library
Microsoft Outlook [Your Version] Object Library
Code
Try to change how the Excel App is initialized, using this:
Dim objExcelApp As New Excel.Application
Instead of:
Dim objExcelApp As Excel.Application
So your code will look like this:
Private Sub objMails_ItemAdd(ByVal Item As Object)
Dim objMail As Outlook.MailItem
Dim strExcelFile As String
Dim objExcelApp As New Excel.Application
Dim objExcelWorkBook As Excel.Workbook
Dim objExcelWorkSheet As Excel.Worksheet
Dim nNextEmptyRow As Integer
Dim strColumnB As String
Dim strColumnC As String
Dim strColumnD As String
Dim strColumnE As String
If Item.Class = olMail Then
Set objMail = Item
End If
'Specify the Excel file which you want to auto export the email list
'You can change it as per your case
strExcelFile = "H:\SF_Mail\Emails.xlsx"
'Get Access to the Excel file
Set objExcelWorkBook = objExcelApp.Workbooks.Open(strExcelFile)
Set objExcelWorkSheet = objExcelWorkBook.Sheets("Sheet1")
'Get the next empty row in the Excel worksheet
nNextEmptyRow = objExcelWorkSheet.Range("B" & objExcelWorkSheet.Rows.Count).End(xlUp).Row + 1
'Specify the corresponding values in the different columns
strColumnB = objMail.SenderName
strColumnC = objMail.SenderEmailAddress
strColumnD = objMail.Subject
strColumnE = objMail.ReceivedTime
'Add the vaules into the columns
objExcelWorkSheet.Range("A" & nNextEmptyRow) = nNextEmptyRow - 1
objExcelWorkSheet.Range("B" & nNextEmptyRow) = strColumnB
objExcelWorkSheet.Range("C" & nNextEmptyRow) = strColumnC
objExcelWorkSheet.Range("D" & nNextEmptyRow) = strColumnD
objExcelWorkSheet.Range("E" & nNextEmptyRow) = strColumnE
'Fit the columns from A to E
objExcelWorkSheet.Columns("A:E").AutoFit
'Save the changes and close the Excel file
objExcelWorkBook.Close SaveChanges:=True
objExcelApp.Quit 'Quit Excel application
End Sub
Notes
Usually it's a bad idea to use the instruction On Error Resume Next, because it suppresses every error you get on runtime execution. However, there're some exceptions to the rule and you can check #FunThomas answer for clarification.
This is not really an answer but too long for a comment to the answer of #Louis and the following discussion.
On Error Resume Next usually is evil, but sometimes it is the best way to deal with a statement that might fail. In this case, the command Set objExcelApp = GetObject(, "Excel.Application") will assign a running instance of Excel to the variable objExcelApp, but will fail (and throw an error) if Excel is currently not active. The following If Error <> 0 Then checks if an error occurred and if yes, it will open a new Excel instance and assign it to objExcelApp.
At that point, Excel should be available to the Macro, either an existing or a new Instance. An exception could only be if Excel is not available at all (not installed) or cannot be started (out of memory). However, the On Error Resume Next is still active and will continue to ignore all runtime errors, and that is bad. So, after the the assignment of the variable, revert to the standard error handling and see what fails:
'Get Access to the Excel file
On Error Resume Next
Set objExcelApp = GetObject(, "Excel.Application")
If Error <> 0 Then
Set objExcelApp = CreateObject("Excel.Application")
End If
On Error Goto 0
Currently my code listed below will copy body information from an incoming email and open the designated excel sheet and copy the contents onto the excel sheet and close it. I would also like to save attachments from incoming email to this designated path :C:\Users\ltorres\Desktop\Projects
I have tried this, but this code will not incorporate with outlook. I would have to run it with excel
Public Sub saveAttachtoDisk (itm As Outlook.MailItem)
Dim objAtt As Outlook.Attachment
Dim saveFolder As String
Dim dateFormat As String
saveFolder = "C:\Users\ltorres\Desktop\Projects"
dateFormat = Format(Now, "yyyy-mm-dd H-mm")
For Each objAtt In itm.Attachments
objAtt.SaveAsFile saveFolder & "\" & dateFormat & objAtt.DisplayName
Set objAtt = Nothing
Next
End Sub
Const xlUp As Long = -4162
Sub ExportToExcel(MyMail As MailItem)
Dim strID As String, olNS As Outlook.NameSpace
Dim olMail As Outlook.MailItem
Dim strFileName As String
'~~> Excel Variables
Dim oXLApp As Object, oXLwb As Object, oXLws As Object
Dim lRow As Long
strID = MyMail.EntryID
Set olNS = Application.GetNamespace("MAPI")
Set olMail = olNS.GetItemFromID(strID)
'~~> Establish an EXCEL application object
On Error Resume Next
Set oXLApp = GetObject(, "Excel.Application")
'~~> If not found then create new instance
If Err.Number <> 0 Then
Set oXLApp = CreateObject("Excel.Application")
End If
Err.Clear
On Error GoTo 0
'~~> Show Excel
oXLApp.Visible = True
'~~> Open the relevant file
Set oXLwb = oXLApp.Workbooks.Open("C:\Users\ltorres\Desktop\Projects\Project 2\TemplateFinal\lighting.xlsm")
'~~> Set the relevant output sheet. Change as applicable
Set oXLws = oXLwb.Sheets("Multiplier")
lRow = oXLws.Range("A" & oXLws.Rows.Count).End(xlUp).Row + 1
'~~> Write to outlook
With oXLws
lRow = .Range("A" & .Rows.Count).End(xlUp).Row + 1
Dim MyAr() As String
MyAr = Split(olMail.Body, vbCrLf)
For i = LBound(MyAr) To UBound(MyAr)
.Range("A" & lRow).Value = MyAr(i)
lRow = lRow + 1
Next i
'
End With
'~~> Close and Clean up Excel
oXLwb.Close (True)
oXLApp.Quit
Set oXLws = Nothing
Set oXLwb = Nothing
Set oXLApp = Nothing
Set olMail = Nothing
Set olNS = Nothing
End Sub
To add to #Om3r response, you could add this code (untested) to the ThisOutlookSession module:
Private WithEvents objNewMailItems As Outlook.Items
Dim WithEvents TargetFolderItems As Items
Private Sub Application_Startup()
Dim ns As Outlook.NameSpace
Set ns = Application.GetNamespace("MAPI")
'Update to the correct Outlook folder.
Set TargetFolderItems = ns.Folders.item("Mailbox - Luis") _
.Folders.item("Inbox") _
.Folders.item("Lighting Emails").Items
End Sub
Sub TargetFolderItems_ItemAdd(ByVal item As Object)
SaveAtmt_ExportToExcel item
End Sub
This will watch the Lighting Emails folder (or whatever folder you choose) and execute the SaveAtmt_ExportToExcel procedure whenever an email arrives in that folder.
This will mean that Excel will open and close for each email. It will also interrupt whatever else you're doing to open Excel and execute - so will probably want to update so it only opens Excel once and to run the Outlook rule to place the emails in the correct folder once a day rather than always on.
Try it this way...
Update SaveFolder = "c:\temp\" and Workbooks.Open("C:\Temp\Book1.xlsx")
Tested on Outlook 2010
Public Sub SaveAtmt_ExportToExcel(Item As Outlook.MailItem)
Dim Atmt As Outlook.Attachment
Dim SaveFolder As String
Dim DateFormat As String
Dim strID As String, olNS As Outlook.NameSpace
Dim olMail As Outlook.MailItem
Dim strFileName As String
'~~> Excel Variables
Dim oXLApp As Object, oXLwb As Object, oXLws As Object
Dim lRow As Long
Dim i As Long
SaveFolder = "c:\temp\"
DateFormat = Format(Now, "yyyy-mm-dd H mm")
For Each Atmt In Item.Attachments
Atmt.SaveAsFile SaveFolder & "\" & DateFormat & " " & Atmt.DisplayName
Next
strID = Item.EntryID
Set olNS = Application.GetNamespace("MAPI")
Set olMail = olNS.GetItemFromID(strID)
'~~> Establish an EXCEL application object
On Error Resume Next
Set oXLApp = GetObject(, "Excel.Application")
'~~> If not found then create new instance
If Err.Number <> 0 Then
Set oXLApp = CreateObject("Excel.Application")
End If
Err.Clear
On Error GoTo 0
'~~> Show Excel
oXLApp.Visible = True
'~~> Open the relevant file
Set oXLwb = oXLApp.Workbooks.Open("C:\Temp\Book1.xlsx")
'~~> Set the relevant output sheet. Change as applicable
Set oXLws = oXLwb.Sheets("Multiplier")
lRow = oXLws.Range("A" & oXLws.Rows.Count).End(xlUp).Row + 1
'~~> Write to outlook
With oXLws
lRow = .Range("A" & .Rows.Count).End(xlUp).Row + 1
Dim MyAr() As String
MyAr = Split(olMail.body, vbCrLf)
For i = LBound(MyAr) To UBound(MyAr)
.Range("A" & lRow).Value = MyAr(i)
lRow = lRow + 1
Next i
'
End With
'~~> Close and Clean
oXLwb.Close (True)
oXLApp.Quit
Set oXLws = Nothing
Set oXLwb = Nothing
Set oXLApp = Nothing
Set olMail = Nothing
Set olNS = Nothing
Set Atmt = Nothing
End Sub
I wish to extract the filenames of the attachments I have received into the public folder and extract ( paste ) them into the excel file for easy analysis.
I have the below code however it is only selecting details of 1 email.
I wish to understand where it does wrong.
Option Explicit
Sub CopyToExcel()
Dim xlApp As Object
Dim xlWB As Object
Dim xlSheet As Object
Dim rCount As Long
Dim bXStarted As Boolean
Dim enviro As String
Dim strPath As String
Dim currentExplorer As Explorer
Dim Selection As Selection
Dim olItem As Outlook.MailItem
Dim myAttachments As Outlook.Attachments
Dim j As Long
Dim i As Integer
Dim Report As String
Dim attachment As attachment
Dim obj As Object
Dim strColB, strColC, strColD, strColE, strColF As String
' Get Excel set up
enviro = CStr(Environ("USERPROFILE"))
'the path of the workbook
strPath = enviro & "\Documents\test.xlsx"
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 input the data
Set xlWB = xlApp.Workbooks.Open(strPath)
Set xlSheet = xlWB.Sheets("Sheet1")
' Process the message record
On Error Resume Next
'Find the next empty line of the worksheet
rCount = xlSheet.Range("B" & xlSheet.Rows.Count).End(-4162).Row
' get the values from outlook
Set currentExplorer = Application.ActiveExplorer
Set Selection = currentExplorer.Selection
For Each obj In Selection
Set olItem = obj
Set myAttachments = olItem.Attachments
'collect the fields
Next
For Each Selection In Selection
If Selection.Class = olMail Then
End If
For Each attachment In olItem.Attachments
Report = strColC & GetAttachmentInfo(attachment)
strColB = olItem.Attachments.Count
strColD = olItem.SenderEmailAddress
strColE = olItem.Categories
strColF = olItem.ReceivedTime
'write them in the excel sheet
xlSheet.Range("B" & rCount) = strColB
xlSheet.Range("c" & rCount) = Report
xlSheet.Range("d" & rCount) = strColD
xlSheet.Range("e" & rCount) = strColE
xlSheet.Range("f" & rCount) = strColF
'Next row
rCount = rCount + 1
Next
Next
xlWB.Close 1
If bXStarted Then
xlApp.Quit
End If
Set olItem = Nothing
Set obj = Nothing
Set currentExplorer = Nothing
Set xlApp = Nothing
Set xlWB = Nothing
Set xlSheet = Nothing
End Sub
Public Function GetAttachmentInfo(attachment As attachment)
On Error GoTo On_Error
Dim Report
Dim strColA, strColB, strColC, strColD, strColE, strColF As String
GetAttachmentInfo = ""
Report = strColA & "Display Name: " & attachment.DisplayName
Report = strColC & "File Name: " & attachment.filename
GetAttachmentInfo = Report
Exiting:
Exit Function
On_Error:
MsgBox "error=" & Err.Number & " " & Err.Description
Resume Exiting
End Function
I do not have access to Outlook at the moment so the following is from studying the macro rather than trying to run it.
Public Function GetAttachmentInfo(attachment As attachment)
You need As String at the end if you want a value returned. You are using attachment both as a keyword and as the name of a parameter. Please rename the parameter.
Report = strColA & "Display Name: " & attachment.DisplayName
Report = strColC & "File Name: " & attachment.filename
strColA and strColA have be declared with a Dim statement but have not been given values so are blank. The second statement overwrites the value of Report set by the first.
I see examples of your use of On Error repeatedly. I did the same until I realised it was totally unhelpful. During development, you want the interpreter to stop on the statement giving the error so you know what to correct. In a production macro, released to non-technical users, you need something more friendly. I suggest you delete this code.
I cannot see why you are getting the name of the first attachment but not the other attachments. I suggest you correct these errors and then repost your revised code.