I am trying to export a report in an from an Access database to multiple email address using a table and a report I have produced. Below is the code I have been using to accomplish this.
Function EmailNotification()
On Error GoTo Err_EmailNotification
Dim olApp As Object
Dim olMail As Object
Set olApp = CreateObject("Outlook.Application")
Set olMail = olApp.CreateItem(olMailItem)
Dim EmailList As String
Dim EmailList2 As String
Dim objOutlookRecip As Object
Dim objOutlookRecip2 As Object
Dim objOutlookAttach As Object
Const TERMINAL_QUERY = "SELECT EMail " & _
" FROM [EmailList] " & _
" ORDER BY Email;"
Dim dbs As DAO.Database
Dim rst1 As DAO.Recordset
DoCmd.OutputTo acOutputReport, "CarryIn_Email", "PDFFormat(*.pdf)", "Q:\2017\Big E Transportation\Accounting\Advanced Auto\Projects Summary Report.PDF", False, " , acExportQualityPrint"
Set dbs = CurrentDb()
Set rst1 = dbs.OpenRecordset(TERMINAL_QUERY)
With rst1
.MoveFirst
.MoveLast
.MoveFirst
rstX = rst1.RecordCount
If Not (.EOF And .BOF) Then
.MoveFirst
Do Until .EOF
Set olApp = CreateObject("Outlook.Application")
Set olMail = olApp.CreateItem(olMailItem)
With olMail
Set objOutlookRecip = .Recipients.Add(rst1!Email)
objOutlookRecip.Type = olTo
.Subject = "Carry Ins"
SETOBJOUTLOOKATTACH = .Attachments.Add("Q:\2017\Big E Transportation\Accounting\Advanced Auto\Projects Summary Report.PDF")
.Send
End With
.MoveNext
Loop
End If
End With
Exit_EmailNotification:
Exit Function
Err_EmailNotification:
MsgBox Error$
Resume Exit_EmailNotification
End Function
My problem is that this code is not exporting an email with a PDF attached to it, but instead is exporting an email with an email as the attachment.
I want this code to export an email with a PDF attachment, not an email with an email as the attachment.
Functions are procedures used to calculate something and return a result. The function you have above is not returning anything.
A subroutine is a procedure to run through steps in a process and not return a result.
the code provided below should satisfy what you are trying to accomplish:
Public Sub EmailNotification()
Dim olApp As Object
Dim olMail As Object
Dim strExport, strList As String
Dim rst1 As DAO.Recordset
Const TERMINAL_QUERY = "SELECT EMail " & _
"FROM [EmailList] " & _
"ORDER BY Email;"
On Error GoTo ErrorH
'Varibale to update one location for entire code
strExport = "Q:\2017\Big E Transportation\Accounting\Advanced Auto\Projects Summary Report.PDF"
'Ensures strList is empty for below check
strList = Empty
'Outputs the report to PDF using strExport variable
DoCmd.OutputTo acOutputReport, "CarryIn_Email", "PDFFormat(*.pdf)", strExport, False, " , acExportQualityPrint"
'Opens the recordset containing email addresses within const query above
Set rst1 = CurrentDb.OpenRecordset(TERMINAL_QUERY)
'ensure the recordset is fully loaded
rst1.MoveLast
rst1.MoveFirst
'loop to acquire email addresses from query statement, adding ";" to separate each email address
Do While Not rst1.EOF
If strList = Empty Then
strList = rst1![Email]
Else
strList = strList & "; "
End If
rst1.MoveNext
Loop
'Closes recordset and frees object in memory
rst.Close
Set rst = Nothing
'Creates the memory for email objects
Set olApp = CreateObject("Outlook.Application")
Set olMail = olApp.CreateItem(olMailItem)
'Generates email information
With olMail
'olFormatPlain is easier to type in an email with, my opinion only, this line is not needed
.BodyFormat = olFormatPlain
'Who the email is going to, using the strList created during loop above
.To = strList
.CC = "" 'Change if you want a CC
.BCC = "" 'Change is you want a BCC
.Subject = "Carry Ins"
.Body = "" 'Change to what ever you want the body of the email to say
'Attaches the exported file using the variable created at beginning
.Attachments.Add = strExport
.Display 'Use for testing purposes only, note out for live runs
'.Send 'Use for live purposes only, note out for test runs
End With
'Frees email objects stored in memory
Set olMail = Nothing
Set olApp = Nothing
EndCode:
'Ensures all objects are free from memory
If Not rst1 Is Nothing Then
rst1.Close
Set rst1 = Nothing
End If
If Not olApp Is Nothing Then
Set olMail = Nothing
Set olApp = Nothing
End If
Exit Sub
'Error handler to display error infor in message box, resumes end code
'Change is you want/need this to handle specific error numbers
ErrorH:
MsgBox Err.Number & " - " & Err.Description
Resume EndCode
End Sub
Related
I want to loop through a table and to email each user an individually tailored email with their prefix and last name.
It seems to be only emailing the first person on the list.
Design mode
Form mode with dummy data
Private Sub SendEmail_Click()
Dim oOutlook As Outlook.Application
Dim oEmailItem As MailItem
Dim rs As DAO.Recordset
On Error Resume Next
Err.Clear
Set oOutlook = GetObject(, "Outlook.Application")
If Err.Number <> 0 Then
Set oOutlook = New Outlook.Application
End If
Set oEmailItem = oOutlook.CreateItem(olMailItem)
Set rs = CurrentDb.OpenRecordset("SELECT * FROM list_of_emails")
If Not (rs.BOF And rs.EOF) Then
rs.MoveFirst
Do Until rs.EOF = True
With oEmailItem
.To = rs!Email
.Subject = "NKS: Test"
.Body = "Hi " & [Prefix] & " " & [lname] & ":" & vbCrLf & vbCrLf & "This is a test."
.Send
End With
rs.MoveNext
Loop
End If
rs.Close
Set oEmailItem = Nothing
Set oOutlook = Nothing
Set rs = Nothing
End Sub
If I remove the On Error Resume Next, I get the following error when I assign the recipient address (.To = rs!Email):
The item has been moved or deleted.
as the comments indicate you just have a bunch of errors. assuming you have a reference to outlook 16 object library added and Prefix and lname are columns in the list_of_emails table then:
Private Sub SendEmail_Click()
Dim oOutlook As Outlook.Application
Dim oEmailItem As MailItem
Dim rs As DAO.Recordset
'On Error Resume Next
'Err.Clear
'Set oOutlook = GetObject(, "Outlook.Application")
'If Err.Number <> 0 Then
' Set oOutlook = New Outlook.Application
'End If
Set oOutlook = New Outlook.Application 'open outlook before start the loop
Set rs = CurrentDb.OpenRecordset("SELECT * FROM list_of_emails")
If Not (rs.BOF And rs.EOF) Then
rs.MoveFirst
Do Until rs.EOF = True
Set oEmailItem = oOutlook.CreateItem(olMailItem) 'create new email for each email address
With oEmailItem
.To = rs!Email
.Subject = "NKS: Test"
.Body = "Hi " & rs!Prefix & " " & rs!lname & ":" & vbCrLf & vbCrLf & "This is a test."
.Send
End With
rs.MoveNext
Loop
End If
rs.Close
Set oEmailItem = Nothing
Set oOutlook = Nothing
Set rs = Nothing
End Sub
I've been putting this code together for a few days now with some success. My code will save pdf reports by project number so my battle is half won. The second part is where I am needing help getting each pdf report to automatically send to the project's email(Proj Mgr Emial) in the table.
tblEmailProjects
Additionally, while I can generate a single email (should be two) in the ".Display" mode, it attaches all the project's pdf reports instead of just the pdf report belonging to that recipient.
Single email generated by code
Finally, my variable strList causes an Runtime error "'-2147221238 The item has been moved or deleted" even tho it has been declared and set
I think/I hope I am close and would really appreciate any help...
Dim olApp As Object
Dim olMail As Object
Dim strExport As String
Dim strList As String
Set olApp = CreateObject("Outlook.Application")
Set olMail = olApp.CreateItem(olMailItem)
Dim rst As DAO.Recordset
'Public strRptFilter As String ' not need to use a public variable
Set rst = CurrentDb.OpenRecordset("SELECT DISTINCT [Proj_Nbr],[Project Mgr Emial] FROM [TblEmailProjects] ORDER BY [Proj_Nbr];", dbOpenSnapshot)
If rst.RecordCount > 0 Then ' make sure that we have data
rst.MoveFirst
Do While Not rst.EOF
strRptFilter = "[Proj_Nbr] = " & Chr(34) & rst![Proj_Nbr] & Chr(34)
DoCmd.OpenReport "rptProjCost", acViewPreview, , strRptFilter, acHidden ' open the report hidden in preview mode setting the where parameter
DoCmd.OutputTo acOutputReport, "rptProjCost", acFormatPDF, "C:\Users\Lisa Burns\Documents\AJI\Deploy DELPHI Projects\" & rst![Proj_Nbr] & ".pdf" ' save the opened report
DoCmd.Close acReport, "rptProjCost" ' close the report
strExport = "C:\Users\Lisa Burns\Documents\AJI\Deploy DELPHI Projects\" & rst![Proj_Nbr] & ".pdf"
strList = rst![Project Mgr Emial] ' ******ERRORS HERE WHEN ACTUALLY TRYING TO SEND EMAILS INSTEAD OF JUST DISPLAYING.&_
'WHEN DISPLAYING ONLY ONE EMAIL SHOWING LAST EMAIL ADDRESS IN THE RECORDsET*****
With olMail
.To = strList '******ERRORS HERE WHEN ACTUALLY TRYING TO SEND EMAILS INSTEAD OF JUST DISPLAYING
.CC = "" 'Change if you want a CC
.BCC = "" 'Change is you want a BCC
.Subject = "Project Costs for" & "rst![Proj_Nbr]" '****CODE DOES NOT CAPTURE PROJ_NBR...INCORRECT SYNTAX?"
.Body = "Attached, please find your project cost report for project number & rst![Proj_Nbr]." 'Change to what ever you want the body of the email to say
'Attaches the exported file using the variable created at beginning
.Attachments.Add strExport '*****ADDS ALL REPORTS INSTEAD OF FILTERING THE PDF REPORT THAT IS APPROPRIATE FOR THE RECIPIENT****
.Display 'Use for testing purposes only, note out for live runs '.Send 'Use for live purposes only.
End With
DoEvents
rst.MoveNext
Loop
End If ' rst.RecordCount > 0
'Frees email objects stored in memory
Set olMail = Nothing
Set olApp = Nothing
'stop added here
rst.Close
Set rst = Nothing
End Sub
What I will suggest you split your codes into two part. First part will saves pdf to your desired folder and second part will send mail to users with individual attachment. Below is code to send mail to individuals with separate pdf attachment. First test it from an command button then include these codes to your codes. It will be easier then to deploy.
Read this post.
I hope you are aware about Add References Microsoft Outlook x.xx Object Library.
Private Sub cmdSendMails_Click()
Dim oApp As New Outlook.Application
Dim oEmail As Outlook.MailItem
Dim strEmail As String, strAttachment As String
Dim mypath As String
mypath = "C:\Users\Lisa Burns\Documents\AJI\Deploy DELPHI Projects\" 'Change the path with your folder path
Dim db As DAO.Database
Dim rs As DAO.Recordset
Set db = CurrentDb()
Set rs = db.OpenRecordset("SELECT DISTINCT [Proj_Nbr],[Project Mgr Emial] FROM [TblEmailProjects]", dbOpenSnapshot)
On Error Resume Next 'Suppress errors
Do While Not rs.EOF
strAttachment = mypath & rs![Proj_Nbr] & ".pdf" 'Pdf name exactly as employee ID.
strEmail = rs![Project Mgr Emial] 'Email address from table column.
Set oEmail = oApp.CreateItem(olMailItem)
With oEmail
.Recipients.Add strEmail 'Add email address
.Subject = "Your subject text here."
.Body = "Your body text here."
.Attachments.Add strAttachment 'Attach PDF file.
'.Send
.Display 'Use .send to send the mail. Display will show the email editor window.
End With
Set oEmail = Nothing
rs.MoveNext
Loop
rs.Close
Set rs = Nothing
Set db = Nothing
End Sub
I want to send automatic emails to the persons whose emailID will be stored in the fields of a query with my report (same to everyone) as attachment.
I have the query, during compiling it is showing error message "in query expression.
Error 3075
I need to attach my report with every email, but I am not finding a way to delete every time after sending from my local file (I have removed the code related to this, so you can add a new one)
Option Compare Database
Option Explicit
Public Sub sendserialemail()
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim emailto As String
Dim emailcc As String
Dim emailsubject As String
Dim emailtext As String
Dim outapp As Outlook.Application
Dim outmail As Outlook.MailItem
Dim outstarted As Boolean
Dim rpt As Report
Dim pdfmail As String
On Error Resume Next
Set outapp = GetObject(, "outlook.application")
On Error GoTo 0
If outapp Is Nothing Then
Set outapp = CreateObject("outlook.application")
outstarted = True
End If
Set db = CurrentDb
Set rs = db.OpenRecordset("qryeMailOverdueTasks")
DoCmd.OutputTo acOutputReport, "tasks", acFormatPDF, "desktop"
Do Until rs.EOF
emailto = rs.Fields("responsible person").Value
emailcc = "ravikumar.ramadas#plansee.com"
emailsubject = "Pending tasks to complete the issue regarding" & " " & rs.Fields("issue").Value
emailtext = "Hello" & vbCrLf & "Kindly complete the task which is in the attached file to complete the cutomer isue regarding" & " " & rs.Fields("issue").Value
pdfmail = "tasks.pdf"
Set outmail = outapp.CreateItem(olMailItem)
outmail.To = emailto
outmail.CC = emailcc
outmail.Subject = emailsubject
outmail.Body = emailtext
outmail.Attachments = pdfmail
outmail.Send
rs.MoveNext
Loop
rs.Close
Set rs = Nothing
Set db = Nothing
If outstarted Then
outapp.Quit
End If
Set outmail = Nothing
Set outapp = Nothing
End Sub
Code tries to save a pdf named "desktop" to folder db is located in. Then code tries to attach a file named "tasks.pdf" but this file does not exist nor does this specify file path where pdf is located.
Correct code to specify file path and name to save and retrieve.
I have working code that replies to an email in the user's Outlook, based on the subject. If the most recent item is a meeting invite, my code will not retrieve the email I want. Instead it will not pass the meeting invite and will display an error.
Code is as follows.
Sub Display()
Dim Fldr As Outlook.Folder
Dim olfolder As Outlook.MAPIFolder
Dim olMail As Outlook.MailItem
Dim olReply As Outlook.MailItem
Dim olItems As Outlook.Items
Dim i As Integer
Dim signature As String
Set Fldr = Session.GetDefaultFolder(olFolderInbox)
Set olItems = Fldr.Items
olItems.Sort "[Received]", True
For i = 1 To olItems.Count
signature = Environ("appdata") & "\Microsoft\Signatures\"
If Dir(signature, vbDirectory) <> vbNullString Then
signature = signature & Dir$(signature & "*.htm")
Else:
signature = ""
End If
signature = CreateObject("Scripting.FileSystemObject").GetFile(signature).OpenAsTextStream(1, -2).ReadAll
Set olMail = olItems(i)
If InStr(olMail.Subject, Worksheets("Checklist Form").Range("B8")) <> 0 Then
If Not olMail.Categories = "Executed" Then
Set olReply = olMail.ReplyAll
With olReply
.HTMLBody = "<p style='font-family:calibri;font-size:14.5'>" & "Hi Everyone," & "<p style='font-family:calibri;font-size:14.5'>" & "Workflow ID:" & " " & Worksheets("Checklist Form").Range("B6") & "<p style='font-family:calibri;font-size:14.5'>" & Worksheets("Checklist Form").Range("B11") & "<p style='font-family:calibri;font-size:14.5'>" & "Regards," & "</p><br>" & signature & .HTMLBody
.Display
.Subject = "RO Finalized WF:" & Worksheets("Checklist Form").Range("B6") & " " & Worksheets("Checklist Form").Range("B2") & " -" & Worksheets("Fulfillment Checklist").Range("B3")
End With
Exit For
olMail.Categories = "Executed"
End If
End If
Next i
End Sub
Is it possible to bypass the most recent item if the code will not pass the first email. Example: Meeting Invite
Dim olMail As Outlook.MailItem
...
Set olMail = olItems(i)
That Set assignment will not only fail if the first item is a meeting invite, it will fail for any olItems(i) (i.e. any value of i) that is not an Outlook.MailItem instance. That includes anything that can possibly land into an Outlook inbox, including a meeting invite.
One way to go would be to handle the runtime error that's thrown in the specific case where olItems(i) isn't a MailItem:
For i = 1 To olItems.Count
On Error GoTo ErrHandler ' jumps to error-handling subroutine if there's an error
Set olMail = olItems(i)
On Error GoTo 0 ' let any other error blow everything up
...
SkipToNext:
Next i
Exit Sub
ErrHandler:
Debug.Print "Item index " & i & " is not a MailItem; skipping."
Resume SkipToNext
Notice I'm putting the assignment/validation as early as possible in the loop - that way you don't run useless instructions if you're not looking at a MailItem.
Another - better - way to go about it, would be to validate the type of olItems(i):
Dim olItem As Object
'...
For i = 1 To olItems.Count
Set olItem = olItems(i)
If Not TypeOf olItem Is Outlook.MailItem Then Goto SkipToNext
Set olMail = olItem ' essentially a type cast from Object to MailItem
...
SkipToNext:
Next
Alternatively, you can drop that GoTo jump and increase the nesting level instead:
For i = 1 To olItems.Count
Set olItem = olItems(i)
If TypeOf olItem Is Outlook.MailItem Then
Set olMail = olItem ' essentially a type cast from Object to MailItem
...
End If
Next
Note the indentation; feel free to use an indenter if you're not sure how to do this correctly & consistently. Proper indentation is critical for code readability, especially given nested looping & conditional structures (disclaimer: I own that website and the OSS project it's for).
I'm a new VBA user and am trying to accomplish what I've described in the title using the code below.
I think it has something to do with creating dims specifically for cc/bcc/and to, but I'm not quite sure. in one column is a list of emails that have been filtered for based on specific conditions and in the column right next to it is either "" "cc" or "bcc". If it's blank, then it goes into "to" if it's cc" it goes into the .CC field etc. etc.
Sub SendList()
'DIM
Dim olApp As Outlook.Application
Dim olMail As MailItem
Dim CurrFile As String
Dim emailRng As Range, cl As Range
Dim sTo As String
'SET
Set emailRng = ActiveSheet.Range("E3:E100").SpecialCells(xlCellTypeVisible)
For Each cl In emailRng
sTo = sTo & ";" & cl.Value
Next
sTo = Mid(sTo, 2)
Set olApp = New Outlook.Application
Set olMail = olApp.CreateItem(olMailItem)
'UPDATE WORKBOOK BEFORE SENDING
ActiveWorkbook.Save
CurrFile = ActiveWorkbook.Path & "\" & ActiveWorkbook.Name
'Need to find a way to automate to TO CC and BCC
With olMail
.To = sTo
.CC = ""
.BCC = ""
.Subject = "Audit Report XYZ" & " " & "-" & " " & Date
.Body = .Body & "Test" & vbCrLf & "Test2" & vbCrLf & "Test3"
.Attachments.Add "C:\Users\uq050e\Downloads\anyfile.xlsx" 'An audit report
.Display '.Send
End With
Set olMail = Nothing
Set olApp = Nothing
End Sub
It looks like the problem is not with Outlook VBA, but with reading the Excel's content. I'd suggest learning VBA and Excel a bit first, see Getting Started with VBA in Excel 2010.
You can use the Text property of the Range class to get the text for the specified object/cell.