MS Access VBA code to send an Outlook email - vba

I am trying to get Access to send a simple email programatically. I have added the Outlook 16.0 reference. Below is the code. When it gets to the With oMail part, it returns an error: "Application-defined of object-defined error."
It errors on the .ReplyRecipients.Add line. If I comment out that line, then it errors on the .Send line.
Note I am running the TestSend() sub to activate the SendEmailOutlook sub.
Sub TestSend()
Call SendEmailOutlook("myemail#email.com", "Test message", "Test message.")
End Sub
Public Sub SendEmailOutlook(strTo As String, strSubject As String, strBody As String)
On Error GoTo SendEmailOutlookErr
Dim strEmail As String
Dim strMsg As String
Dim oLook As Object
Dim oMail As Object
Set oLook = CreateObject("Outlook.Application")
Set oMail = oLook.createitem(0)
With oMail
.ReplyRecipients.Add "myemail#email.com"
.to = strTo
.htmlbody = strBody
.Subject = strSubject
.Send
End With
Set oMail = Nothing
Set oLook = Nothing
Exit Sub
SendEmailOutlookErrExit:
Exit Sub
SendEmailOutlookErr:
MsgBox Err.Description, vbOKOnly, Err.Source & ":" & Err.Number
Resume SendEmailOutlookErrExit
End Sub

In the code the late binding technology is used, so the COM reference is optional. But if you have already added the Outlook COM refence you may declare all Outlook objects instead of just having the object in the declaration. It can help. Read more about the late and early binding in the Using early binding and late binding in Automation article.
Also the following line of code contains multiple property and method calls:
With oMail
.ReplyRecipients.Add "myemail#email.com"
The code is valid. But it makes sense to declare each property or method on a separate line of code, so you could easily find the faulting one - where exactly the error occurs.
The MailItem.ReplyRecipients property returns a Recipients collection that represents all the reply recipient objects for the Outlook item. Use the Add method to create a new Recipient object and add it to the Recipients object. The Type property of a new Recipient object is set to the default for the associated AppointmentItem, JournalItem, MailItem, or TaskItem object and must be reset to indicate another recipient type.
Set myItem = Application.CreateItem(olMailItem)
Set myRecipient = myItem.Recipients.Add ("Jon Grande")
myRecipient.Type = olCC
Another aspect is how Outlook has been configured to trust applications on a client computer, an application that uses the Outlook object model to access certain data or execute certain actions can invoke security warnings or throw errors when Outlook is automated without any UI. Depending on the type of information or action that the program was attempting to access or execute, there are three different security prompts that applications can invoke through the Object Model Guard: the address book warning, send message warning, and execute action warning. Read more about that in the Outlook Object Model Security Warnings article.

Related

Saving a copy of outlook email (.msg) to a folder after 'Send' is pressed

I have tried the codes below and it was working exactly as I wanted it to be.
http://www.mrexcel.com/forum/excel-questions/361751-visual-basic-applications-saving-email-only-after-send-pushed.html
However, as I was creating this for other colleagues who are using different Excel version, some of my colleagues are having library error. After read around, I believe I need to use late binding instead of early binding so people with different excel version can access the function.
How to I change the code below (to late binding) so that all other version of excel users can also use the function? Copy of the working codes below.
Class Code
Option Explicit
Public WithEvents obj_OL As Outlook.Application
'
Private Sub obj_OL_ItemSend(ByVal Item As Object, Cancel As Boolean)
'// For example, change pathway to suit, such as: //
'// "\\Dacsrv02\rtddata\Advice\TechQueries\TRIM Emails\" & emailname
OutMail.SaveAs ThisWorkbook.Path & _
Application.PathSeparator & _
emailname
'// AFTER the event has been called, explicitly release Outlook. //
Set obj_OL = Nothing
Set OutMail = Nothing
End Sub
Sub Codes
Option Explicit
'// Connect the declared object w/the class module //
Dim cls_OL As New clsOutlook
'// Declare the email msg (mail item) and emailname string as Public, so //
'// that they can be "seen" from any procedures in the class mod. //
Public OutMail As Outlook.MailItem
Public emailname As String
Sub Email_Response()
Dim strbody As String
'// Create our new mail item //
Set OutMail = cls_OL.obj_OL.CreateItem(0)
'// Example substitute //
strbody = "This is just example text"
On Error Resume Next
emailname = "something.msg"
With OutMail
.To = ""
.CC = ""
.BCC = ""
.Subject = "Specific Subject"
.body = strbody
.Display
End With
On Error GoTo 0
End Sub
You cannot (easily) support events using late binding, not in VB script. Whoever is using your code, will need to add the right version of Outlook to the project references.

Outlook attachments send then move

how do I move the files once its been send out successfully to c:\complete
Can I limit the attachments to 10 attachments per email.
each file size is like 300kb
Option Explicit
Sub SendMessage(Optional AttachmentPath)
Dim objOutlook As Outlook.Application
Dim objOutlookMsg As Outlook.MailItem
Dim objOutlookRecip As Outlook.Recipient
Dim objOutlookAttach As Outlook.Attachment
Dim objOutlookFile As String
'// Attachment Path
AttachmentPath = "C:\Reports\"
'// Create the Outlook session.
Set objOutlook = CreateObject("Outlook.Application")
'// Create the message.
Set objOutlookMsg = objOutlook.CreateItem(olMailItem)
With objOutlookMsg
'// Add the To recipient(s) to the message.
Set objOutlookRecip = .Recipients.Add("omar")
Set objOutlookRecip = .Recipients.Add("omar")
objOutlookRecip.Type = olTo
'// Add the CC recipient(s) to the message.
Set objOutlookRecip = .Recipients.Add("omar")
objOutlookRecip.Type = olCC
'// Set the Subject, Body, and Importance of the message.
.Subject = "Reports"
.Body = "the Attached reports are complete !" & vbCrLf & vbCrLf
.Importance = olImportanceHigh '//High importance
'// Add attachments to the message.
objOutlookFile = Dir(AttachmentPath & "*.*")
Do While Len(objOutlookFile) > 0
.Attachments.Add AttachmentPath & objOutlookFile
objOutlookFile = Dir
Loop
'// Resolve each Recipient's name.
For Each objOutlookRecip In .Recipients
objOutlookRecip.Resolve
If Not objOutlookRecip.Resolve Then
objOutlookMsg.Display
End If
Next
'//.DeleteAfterSubmit = True
'//.Send
.Display
End With
Set objOutlookMsg = Nothing
Set objOutlook = Nothing
End Sub
It is not clear where you run the VBA macro code (Outlook, Word, Excel and etc.).
Anyway, there is no need to create a new Outlook Application instance in the Outlook VBA macro:
'// Create the Outlook session.
Set objOutlook = CreateObject("Outlook.Application")
Instead, you can use the Application property, for example:
'// Create the message.
Set objOutlookMsg = Application.CreateItem(olMailItem)
You can use the FileSystemObject for managing files on the disk. See Accessing Files with FileSystemObject for more information.
Also the Outlook object model provides the BeforeAttachmentAdd event for Outlook items which is fired before an attachment is added to an instance of the parent object. It provides an instance of the Attachment class to be added and the Cancel parameter which can be used to cancel the action. Just set to true to cancel the operation; otherwise, set to false to allow the Attachment to be added.
sorry one more question, can I stop outgoing email if there is no files in c:\reports\
The best way is to check the folder before runnig the VBA macro. You can use the FileSystemObject to get the job done.
The Application class from the Outlook object model provides the ItemSend event which is fired whenever an Microsoft Outlook item is sent, either by the user through an Inspector (before the inspector is closed, but after the user clicks the Send button) or when the Send method for an Outlook item, such as MailItem, is used in a program. It provides the item reference being sent and the Cancel parameter. If the event procedure sets the Cancel argument to true, the send action is not completed and the inspector is left open.
You can use both these events to check out whatever you need.
Finally, you may find the Getting Started with VBA in Outlook 2010 article in MSDN helpful.

Appening to Subject and Send message Outlook VBA

I'm trying to create a macro that will add some text into the subject of a message and then send the message. I ahve created a button on the ribbon that the user will click to add (Secure) into the subject line and send the message.
I'm using the following which I've put together from several sources I found online.
Sub InsertSubject()
Dim objMsg As Outlook.MailItem
'Get the currently open message'
Set objMsg = Outlook.Application.ActiveInspector.CurrentItem
objMsg.Subject = CurrentItem.Subject & "(Secure) "
'Destroy the object to avoid memory leaks'
objMsg.Send
Set objMsg = Nothing
End Sub
when I run this I get a Run-time error 424 Object Required. It appears to have an issue with the following line
objMsg.Subject = CurrentItem.Subject & "(Secure) "
If I remove the CurrentItem.Subject, the code works but obviously just replaces what ever subject with (Secure).
Any help would be greatly appreciated.
I think you are intending to do objMsg.Subject = objMsg.Subject & "(Secure) ".
Note that you are trying to use CurrentItem which is not necessarily the same as Outlook.Application.ActiveInspector.CurrentItem. I'm not that familiar with Outlook object model but I bet CurrentItem when called on it's own is not valid.

Suppress dialog warning that a program is trying to access my mails

I am following the code from this page: How to create a script for the Rules Wizard in Outlook
This is what I have:
Public Sub GetMails(Item As Outlook.MailItem)
MsgBox "Mail message arrived: " & Item.SenderEmailAddress
MsgBox "Mail message arrived: " & Item.Subject
MsgBox "Mail message arrived: " & Item.Body
End Sub
I set a rule to run this macro. Every time this script runs there is a dialog about how a program is trying to access my mails.
How can I get rid of this using VBA or is there any configuration option in Outlook so that this does not appear?
I have googled for this and found some sites giving code for C# and VB.net but none for VBA.
This was added to prevent malicious scripts from turning Outlook into a mass mailer or other bad things.
You can turn this off on your workstation, but if you want to distribute your application to other users, you can get rid of this only by creating your own Outlook Addin or use a 3rd-party tool like Redemption.
Try this
Tools-->Macro-->Security-->macro security-->No security
Tools-->Macro-->Security-->Programmatic Access
Then choose Never warn me about suspicious activity.
I found this somewhere and it works:
Sub SaveAttachment(myItem As Outlook.MailItem)
' Remove ay attachments for the email and save them in a
' local folder. If there are any erros on the saveing then
' attachments are left in place.
Dim myAttachments As Object
Dim myOrt As String
Dim strID As String
Dim olNS As Outlook.NameSpace
Dim oMail As Outlook.MailItem
Dim fs As Object
' We need to get the mail item object from the application
' object to avoid warning messages
strID = myItem.EntryID
Set olNS = Application.GetNamespace("MAPI")
Set oMail = olNS.GetItemFromID(strID)

When is a MailItem not a MailItem? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I have written a message handler function in Outlook's Visual Basic (we're using Outlook 2003 and Exchange Server) to help me sort out incoming email.
It is working for me, except sometimes the rule fails and Outlook deactivates it.
Then I turn the rule back on and manually run it on my Inbox to catch up. The rule spontaneously fails and deactivates several times a day.
I would love to fix this once and for all.
This code showed me the different TypeNames that were in my Inbox:
Public Sub GetTypeNamesInbox()
Dim myOlItems As Outlook.Items
Set myOlItems = application.GetNamespace("MAPI").GetDefaultFolder(olFolderInbox).Items
Dim msg As Object
For Each msg In myOlItems
Debug.Print TypeName(msg)
'emails are typename MailItem
'Meeting responses are typename MeetingItem
'Delivery receipts are typename ReportItem
Next msg
End Sub
HTH
I use the following VBA code snippet in other Office Applications, where the Outlook Library is directly referenced.
' Outlook Variables
Dim objOutlook As Outlook.Application: Set objOutlook = New Outlook.Application
Dim objNameSpace As Outlook.NameSpace: Set objNameSpace = objOutlook.GetNamespace("MAPI")
Dim objFolder As MAPIFolder: Set objFolder = objNameSpace.PickFolder()
Dim objMailItem As Outlook.MailItem
Dim iCounter As Integer: iCounter = objFolder.Items.Count
Dim i As Integer
For i = iCounter To 1 Step -1
If TypeOf objFolder.Items(i) Is MailItem Then
Set objMailItem = objFolder.Items(i)
With objMailItem
etc.
have written a message handler function in Outlook's Visual Basic (we're using Outlook 2003 and Exchange Server) to help me sort out incoming email. It is working for me, except sometimes the rule fails and Outlook deactivates it. Then I turn the rule back on and manually run it on my Inbox to catch up. The rule spontaneously fails and deactivates several times a day. I would love to fix this once and for all.
Here is the code stripped of the functionality, but giving you an idea of how it looks:
Public WithEvents myOlItems As Outlook.Items
Public Sub Application_Startup()
' Reference the items in the Inbox. Because myOlItems is declared
' "WithEvents" the ItemAdd event will fire below.
' Set myOlItems = Outlook.Session.GetDefaultFolder(olFolderInbox).Items
Set myOlItems = Application.GetNamespace("MAPI").GetDefaultFolder(olFolderInbox).Items
End Sub
Private Sub myOlItems_ItemAdd(ByVal Item As Object)
On Error Resume Next
If TypeName(Item) = "MailItem" Then
MyMessageHandler Item
End If
End Sub
Public Sub MyMessageHandler(ByRef Item As MailItem)
Dim strSender As String
Dim strSubject As String
If TypeName(Item) <> "MailItem" Then
Exit Sub
End If
strSender = LCase(Item.SenderEmailAddress)
strSubject = Item.Subject
rem do stuff
rem do stuff
rem do stuff
End Sub
One error I get is "Type Mismatch" calling MyMessageHandler where VB complains that Item is not a MailItem. Okay, but TypeName(Item) returns "MailItem", so how come Item is not a MailItem?
Another one I get is where an email with an empty subject comes along. The line
strSubject = Item.Subject
gives me an error. I know Item.Subject should be blank, but why is that an error?
Thanks.
My memory is somewhat cloudy on this, but I believe that a MailItem is not a MailItem when it is something like a read receipt. (Unfortunately, the VBA code that demonstrated this was written at another job and isn't around now.)
I also had code written to process incoming messages, probably for the same reason you did (too many rules for Exchange, or rules too complex for the Rules Wizard), and seem to recall running into the same problem you have, that some items seemed to be from a different type even though I was catching them with something like what you wrote.
I'll see if I can produce a specific example if it will help.
There are many types of items that can be seen in the default Inbox.
In the called procedure, assign the incoming item to an Object type variable. Then use TypeOf or TypeName to determine if it is a MailItem. Only then should your code perform actions that apply to emails.
i.e.
Dim obj As Object
If TypeName(obj) = "MailItem" Then
' your code for mail items here
End If
Dim objInboxFolder As MAPIFolder
Dim oItem As MailItem
Set objInboxFolder = GetNamespace("MAPI").GetDefaultFolder(olFolderInbox)
For Each Item In objInboxFolder.Items
If TypeName(Item) = "MailItem" Then
Set oItem = Item
next
why not use a simple error handler for the code? Seriously. You could write an error for each read of a property or object that seems to fail. Then have it Resume no matter what. No need for complex error handling. Think of a test that shows an empty subject. Since you don't know what value it will return, if any, and it seems to error on an empty or blank subject, you need to picture it as a simple test with a possible error. Run the test as an if statement (one in which you will get an error anyway), and have the program resume on error.
On Error Resume Next
If object.subject = Null 'produces an error when subject is null, otherwise allows a good read
strSubject = "" 'sets the subject grab string to a null or empty string as a string
Else
strSubject = object.subject 'Sets the subject grab string to the subject of the message\item
End If