Send Email using VBA 'Function Run-time error 438' - ms-access

I'm trying to send email using VBA code, the function is working and the email is sent, but the problem is when function end 'Run-time error 438 object doesn't support this property or method' appears
here is the code:
Public Function SendEmail(ItemName As String, Total_Qnty As Integer)
Set iMsg = CreateObject("CDO.Message")
Set iConf = CreateObject("CDO.Configuration")
Set Flds = iConf.Fields
' send one copy with Google SMTP server (with autentication)
schema = "http://schemas.microsoft.com/cdo/configuration/"
Flds.Item(schema & "sendusing") = 2
Flds.Item(schema & "smtpserver") = "smtp.gmail.com"
Flds.Item(schema & "smtpserverport") = 465
Flds.Item(schema & "smtpauthenticate") = 1
Flds.Item(schema & "sendusername") = "example#gmail.com"
Flds.Item(schema & "sendpassword") = "*****"
Flds.Item(schema & "smtpusessl") = 1
Flds.Update
With iMsg
.To = "example#hotmail.com"
.From = "example#gmail.com"
.Subject = "Mail from gmail"
.HTMLBody = "The Stock Safty Level of Item: " & ItemName & " is DOWN, The total quantity you have is: " & Total_Qnty & "!!"
Set .Configuration = iConf
.Send
End With
Set iMsg = Nothing
Set iConf = Nothing
Set Flds = Nothing
End Function
Pleased any ideas .. Thank you

Most probably it's a binary compatibility issue between components.
Microsoft says "Run Time Error 438 - Object Doesn't Support this Property or Method:
The most common cause of error 438 is not maintaining binary compatibility between successive versions of your components. Each COM interface has an associated GUID that is called an interface ID (IID). Each coclass has an associated GUID that is called class ID (CLSID). When you compile an ActiveX component in Visual Basic, the CLSIDs and IIDs are compiled into the component's type library."
In this link it's explained how to solve a similar problem:
http://www.vbforums.com/showthread.php?460591-RESOLVED-Runtime-error-438-Object-doesn-t-support-this-property-or-method

Reverse the order of these:
Set iMsg = Nothing
Set iConf = Nothing
Set Flds = Nothing
Flds is a member of iConf which, currently, you have already disposed of.

Related

How to include "mailto" in body of email?

I send an email through Outlook. I am trying to put an email address link within the body of the email, so that one can click on it and an email opens.
E.g. "If you have any questions, please contact us at ABC", where the "ABC" is the link that represents email address, ABC#gmail.com (not the real address).
I understand, from scouring the web, this is the syntax:
<a href="mailto:ABC#gmail.com\>ABC\</a>
I borrowed code that uses HTML to format a message in the body of an email, and replaced a line with what I wanted.
I received a Compile Error (which I think is actually a syntax error in this case?).
When debugging, the "mailto" text was highlighted.
My insertion:
ABC mailbox
.HTMLBody = "\<HTML\>\<BODY\>\<a href="mailto:ABC#gmail.com"\>ABC mailbox\</a>\</BODY\>\</HTML\>"
Sub SendEmailformattext()
'Update by Extendoffice.com
Dim xRg As Range
Dim xRgEach As Range
Dim xRgVal As String
Dim xAddress As String
Dim OutlookApp As Object
Dim MItem As Object
On Error Resume Next
xAddress = ActiveWindow.RangeSelection.Address
Set xRg = Application.InputBox("Please select email address range", "KuTools For Excel", xAddress, , , , , 8)
If xRg Is Nothing Then Exit Sub
Application.ScreenUpdating = False
Set OutlookApp = CreateObject("Outlook.Application")
Set MItem = OutlookApp.CreateItem(olMailItem)
Set xRg = xRg.SpecialCells(xlCellTypeConstants, xlTextValues)
For Each xRgEach In xRg
xRgVal = xRgEach.Value
If xRgVal Like "?*#?*.?\*" Then
Set MItem = xOutApp.CreateItem(olMailItem)
With MItem
.Display
.To = xRgVal
.Subject = "Test"
.HTMLBody = "\<HTML\>\<BODY\>\<a href="mailto:ABC#gmail.com"\>ABC mailbox\</a>\</BODY\>\</HTML\>"
'.Send
End With
End If
Next
Set xMailOut = Nothing
UNCLASSIFIED
Set xOutApp = Nothing
Application.ScreenUpdating = True
End Sub
The original code worked so I know the mailto text is the problem.
Use the Chr(34) function if you need to use double quotes in the string:
.HTMLBody = "\<HTML\>\<BODY\>\**<a href="& Chr(34) & "mailto:ABC#gmail.com" & Chr(34) & "\>ABC mailbox\</a>**\</BODY\>\</HTML\>"

Access 2013 - Send an email automatically with outlook and Windows Task Scheduler

I have an access macro that runs a set of Netezza queries and uploads the results to a database. It then opens and refreshes an Excel file that utilizes this data and saves the file in a couple of locations. Finally it composes an automated email and sends it to a distribution list. When I manually run the macro, everything works 100% perfectly.
In order to make my life a bit easier, I am using Windows Task Scheduler (Windows 10) to automatically fire the macro once a day, and this is where my issue lies. Task Scheduler fires the macro off without a hitch, all of the queries refresh, the excel files are saved, but the e-mail is not sent.
Here is the code SendOutlookEmail code that I'm using
Sub sendOutlookEmail()
Dim oApp As Outlook.Application
Dim oMail As MailItem
Dim SpDate As String
Dim Signature As String
Dim StrPath As String
Dim StrFilter As String
Dim StrFile As String
SpDate = Format(Now() - 1, "yyyy-mm-dd")
Set oApp = CreateObject("Outlook.application")
Set oMail = oApp.CreateItem(olMailItem)
With oMail
.Display
End With
Signature = oMail.HTMLBody
With oMail
.SentOnBehalfOfName = "My Email"
.To = "CCO Reporting"
.Subject = "AHT - ACW Dashboard - " & SpDate
.HTMLBody = "<span LANG=EN>" _
& "<font FACE=SegoeUI SIZE = 3>" _
& "The IB/OB AHT - ACW reports have been updated and placed in the following folder:" _
& "<br><br>" _
& "<a href='File Location'>File Location</a>" & "<br><br><br></font></span>" _
& Signature
'.Attachments.Add (StrPath & StrFile)
'.Display
.Send
End With
On Error GoTo 0
Set oMail = Nothing
Set oApp = Nothing
End Sub
Here is the task scheduler settings
Task Scheduler
Possibly Outlook just doesn't have enough time to send the message, as it instantly gets closed after the message is moved to the outbox (.send doesn't send the message as far as I know, but just moves it to the outbox and triggers a send for all items in there).
Try to manually add a send/receive, to make Access wait for Outlook to actually send the mails (add this to your vba before the Set oApp = Nothing):
' Synchronizes (ie sends/receives) OL folders.
' Ref: http://msdn.microsoft.com/en-us/library/ff863925.aspx
Dim objNsp As Outlook.NameSpace
Dim colSyc As Outlook.SyncObjects
Dim objSyc As Outlook.SyncObject
Dim i As Integer
On Error GoTo SyncOL_Err
Set objNsp = oApp.Application.GetNamespace("MAPI")
Set colSyc = objNsp.SyncObjects
For i = 1 To colSyc.Count
Set objSyc = colSyc.Item(i)
Debug.Print objSyc.Name
objSyc.start
Next
Set objNsp = Nothing: Set colSyc = Nothing: Set objSyc = Nothing

Data from Access will not copy to Word bookmark

I have data from a query name "GrabInfoOfMostRecent" and I am using it as a source for Word to fill in a document with bookmarks. However, once I get to any non-text data, I get error 438 "Object doesn't support this property or method".
Specifically:
For "MRN"I have tried all variations of .Range.Text/Value/Value2 and cannot get the number MRN to fill into the appropriate Bookmark.
For "Diagnosis1", I get an Error13 "Type Mismatch" but I don't know why. It is defined as "Short Text" just as all previous text entries are.
Anyone with any help, I would be deeply appreciative.
Sub WordAutomation()
On Error GoTo HandleError
' Object variables for Automation stuff
' declare them like so during development
' you need to set a reference to the applications
'Dim objWord As New Word.Application
' declare them like this when development is complete
' references no longer necessary
Dim objWord As Object
' Object variables for database access
Dim db As DAO.Database
Dim rstPatientVisit As DAO.Recordset
Dim rsReportData As DAO.Recordset
Dim rsExclusions As DAO.Recordset
' Scalar variables
Dim strsql As String
Dim strFile As String
Dim conPath As String
Dim wdGoToBookmark As Integer
'find the folder where the database resides
Set db = CurrentDb
Set rsReportData = db.OpenRecordset("GrabInfoOfMostRecent")
strFile = db.Name
conPath = Mid(strFile, 1, Len(strFile) - Len(Dir(strFile)))
'Step through the records one at a time, creating a Word
'document for each.
'Do While Not rsReportData.EOF
'--create new word document
Set objWord = CreateObject("Word.Application")
objWord.Documents.Add conPath & "TunTemplate.dotx"
' Make both Word and the document are visible
objWord.Visible = True
objWord.Windows(1).Visible = True
'find bookmarks and insert values
With objWord.ActiveDocument.Bookmarks
.Item("RDFirst").Range.Text = rsReportData!RDFirstName
.Item("RDLast").Range.Text = rsReportData!RDLastName
.Item("PFirstName").Range.Text = rsReportData!PVFirstName
.Item("PLastName").Range.Text = rsReportData!PVLastName
.Item("MRN").Range.Value2 = rsReportData!MRN
.Item("RDAddress").Range.Text = rsReportData!RDAddress
.Item("PAddress").Range.Text = rsReportData!Address
.Item("RDCity").Range.Text = rsReportData!RDCity
.Item("RDCounty").Range.Text = rsReportData!RDCounty
.Item("PCity").Range.Text = rsReportData!City
.Item("PCounty").Range.Text = rsReportData!County
.Item("RDPostalCode").Range.Text = rsReportData!RDPostalCode
.Item("PPostalCode").Range.Text = rsReportData!PostalCode
.Item("Diagnosis1").Range.Text = rsReportData!Diagnosis1
.Item("Treatment1").Range.Text = rsReportData!Treatment1
.Item("Changes1").Range.Text = rsReportData!Changes1
.Item("Diagnosis2").Range.Text = rsReportData!Diagnosis2
.Item("Treatment2").Range.Text = rsReportData!Treatment2
.Item("Changes2").Range.Text = rsReportData!Changes2
.Item("Diagnosis3").Range.Text = rsReportData!Diagnosis3
.Item("Treatment3").Range.Text = rsReportData!Treatment3
.Item("Changes3").Range.Text = rsReportData!Changes3
.Item("Diagnosis4").Range.Text = rsReportData!Diagnosis4
.Item("Treatment4").Range.Text = rsReportData!Treatment4
.Item("Changes4").Range.Text = rsReportData!Changes4
.Item("Diagnosis5").Range.Text = rsReportData!Diagnosis5
.Item("Treatment5").Range.Text = rsReportData!Treatment5
.Item("Changes5").Range.Text = rsReportData!Changes5
.Item("Weight").Range.Text = rsReportData!Weight
.Item("Height").Range.Text = rsReportData!Height
.Item("BMICalc").Range.Text = rsReportData!BMICalc
.Item("Waist").Range.Text = rsReportData!Waist
.Item("BP").Range.Text = rsReportData!BP
.Item("RAcuity").Range.Text = rsReportData!REyeAcuity
.Item("LAcuity").Range.Text = rsReportData!LEyeAcuity
.Item("RRetina").Range.Text = rsReportData!RLensRetina
.Item("LRetina").Range.Text = rsReportData!LLensRetina
.Item("HbA1c").Range.Text = rsReportData!HbA1C
.Item("Creatinine").Range.Text = rsReportData!Creatinine
.Item("TChol").Range.Text = rsReportData!TChol
.Item("UrineACR").Range.Text = rsReportData!UrineACR
.Item("LDL").Range.Text = rsReportData!LDL
.Item("TSH").Range.Text = rsReportData!TSH
.Item("HDL").Range.Text = rsReportData!HDL
.Item("B12").Range.Text = rsReportData!B12
.Item("TG").Range.Text = rsReportData!TG
.Item("EGFR").Range.Text = rsReportData!EGFR
End With
'find and write exclusion data
strsql = "SELECT ReportID, Exclusion " & _
"FROM ExclusionData " & _
"WHERE ReportID=" & rsReportData!ReportID
Set rsExclusions = db.OpenRecordset(strsql)
Do While Not rsExclusions.EOF
With objWord.ActiveDocument.Bookmarks
.Item("exclusions").Range.Text = rsExclusions!Exclusion & vbCrLf
rsExclusions.MoveNext
End With
Loop
rsExclusions.Close
'Save the document and close Word
objWord.ActiveDocument.SaveAs (conPath & rsReportData!MRN & ".doc")
'objWord.Quit
'go to next record for processing
'rsReportData.MoveNext
'Loop
'Tell the user the process is done.
MsgBox "Done!" & vbCrLf & vbCrLf & _
"Look in this directory" & vbCrLf & conPath & vbCrLf & _
"for your documents."
ProcDone:
' clean up our object variables
Set objWord = Nothing
Set rsReportData = Nothing
Set rsExclusions = Nothing
Set db = Nothing
ExitHere:
Exit Sub
HandleError:
'display appropriate error message
Select Case Err.Number
Case 5151 'Word template not found
'Close stranded applications
MsgBox "Word template not found"
Case 5152 'Invalid file name
'Close stranded applications
objWord.ActiveDocument.Close SaveChanges:=False
objWord.Quit
MsgBox "This file or folder does not exist"
Case Else
MsgBox Err.Description, vbExclamation, _
"Error " & Err.Number
End Select
Resume ProcDone
End Sub
Simply with the desire to help you troubleshoot this; I offer the following.
Try converting the problem field into a string using:
.Item("Diagnosis1").Range.Text = CStr(rsReportData!Diagnosis1)
You may also want to display a dialog box with the contents of rsReportData!Diagnosis1:
MsgBox "rsReportData!Diagnosis1 is: " & rsReportData!Diagnosis1 _
, vbOkOnly + vbInformation
To convert null values into zero-length-strings, you can use the following:
.Item("Diagnosis1").Range.Text= IIf(IsNull(rsReportData!Diagnosis1), "", rsReportData!Diagnosis1)

Send HTML-formatted email messages from Access

Is there any way to send a mail in HTML format (and if possible with attachments) when your default mail client isn't Outlook?
Many thanks for any solution.
You should be able to use CDO (Collaboration Data Objects). The code will look something like this:
Option Compare Database
Option Explicit
Sub cdoHtmlTest()
Const urlPrefix = "http://schemas.microsoft.com/cdo/configuration/"
Dim msg As Object ' CDO.Message
Set msg = CreateObject("CDO.Message") ' New CDO.Message
With msg.Configuration.Fields
.Item(urlPrefix & "sendusing") = 2 ' cdoSendUsingPort
.Item(urlPrefix & "smtpserver") = "smtp.example.com"
.Item(urlPrefix & "smtpserverport") = 25
.Item(urlPrefix & "smtpauthenticate") = 1 ' cdoBasic
.Item(urlPrefix & "sendusername") = "mySmtpUserName"
.Item(urlPrefix & "sendpassword") = "mySmtpPassword"
.Item(urlPrefix & "smtpusessl") = False
.Update ' remember to do this step!
End With
With msg
.To = "gord#example.com"
.From = "gord#example.com"
.Subject = "HTML message test"
.HTMLBody = "This is a <strong>TEST</strong>."
.Send
End With
Set msg = Nothing
End Sub
For more examples (including how to send attachments), look here.

Send email from Access if DOB is within 'n' days

I needed to make it in access so that I send an email to a certain customer when their date of birth is within 3 days.
Dim rs as dao.recordset
set rs = currentdb.openrecordset(“DiscountEmail”)
with rs
if .eof and .bof then (No Records found for this query.)
Msgbox “ No emails will be sent because there are no records from the query ‘DiscountEmail’ “
else
do until .eof
DoCmd.SendObject acSendNoObject, , , ![Email Address Field], , , “Happy Birthday!”, “Hello ” & ![First Name Field] & _
“, ” & Chr(10) & “Come in on your birthday and receive a 10% discount!”, False
.edit
![Email_Sent_Date] = now()
.update
.movenext
loop
End If
end with
If Not rs Is Nothing Then
rs.Close
Set rs = Nothing
End If
I have this code, but now I just need to make it so that if a certain customer's birthday (In my table 'CustomerInfo') is within 3 days, it sends them an email saying that they can come in on their birthday and receive a discount.
Also, I want to make it so that this happens automatically (so I don't have to press any button), but so that it sends it only once, and so I can send it again next year.
Thanks in advance! :)
You need to have some event in order to fire this event. An Access database is just a file, so when you're not using it, it's not running any code.
Doing a simple check every time the database is opened, maybe on the first form's On Load event would be the way to go. I assume your DiscountEmail RecordSet is the one querying for emails within the 3 day period.
Your solution is to either put this in the onLoad event for your first form or to use another service. As far as not spamming the emailee more than once, just add a emailSent field or log sent emails to a different table, and handle it after the email is sent.
Example query to find the relevant emails:
Select email from Users Where dateOfBirth between dateAdd("d",-3,Date()) AND dateAdd("d",3,Date());
Do send an email, you could use SMTP and CDO. Create an email function called something like sendEmail
Public Sub SendEmail(strTo as STring, strFrom as String, strSubj as String, strBody as String)
Dim imsg As Object
Dim iconf As Object
Dim flds As Object
Dim schema As String
Set imsg = CreateObject("CDO.Message")
Set iconf = CreateObject("CDO.Configuration")
Set flds = iconf.Fields
' send one copy with SMTP server (with autentication)
schema = "http://schemas.microsoft.com/cdo/configuration/"
flds.Item(schema & "sendusing") = cdoSendUsingPort
flds.Item(schema & "smtpserver") = "mail.myserver.com" 'your info here
flds.Item(schema & "smtpserverport") = 25
flds.Item(schema & "smtpauthenticate") = cdoBasic
flds.Item(schema & "sendusername") = "email#email.com" 'more of your info
flds.Item(schema & "sendpassword") = "password"
flds.Item(schema & "smtpusessl") = False
flds.Update
With imsg
.To = strTo
.From = strFrom
.Subject = strSubj
.HTMLBody = strBody
'.body = strBody
'.Sender = "Sender"
'.Organization = "My Company"
'.ReplyTo = "address#mycompany.com"
Set .Configuration = iconf
.Send
End With
Set iconf = Nothing
Set imsg = Nothing
Set flds = Nothing
End Sub
You could either loop through the resultset of your query and call your sendmail function for each email, or write a quick helper function that fetches and concatenates your email fields into a ";" delimited list, and just send the email once with multiple recipients.
If the essence of your question is about the actual sending of the email message itself, then you may find that DoCmd.SendObject may not be the best method. It has several limitations, most significantly (ref: here)
the message text is limited to 255 characters
it depends on interaction with an email client application (via MAPI, I assume) so it may not work if there is no mail client configured, or if the mail client is not a Microsoft product
Instead, you might consider sending the messages via CDO. There is a good write-up and some ready-to-use VBA code here:
http://www.cpearson.com/excel/Email.aspx