Outlook VBA Incorrectly Replying to Emails in Folder - vba

As referenced from this post, Excel VBA for searching in mails of Outlook, I changed the code slightly to resend all emails to the same recipient in the "sent items" folder.
Function ReplyEmail()
Dim olMail
Dim olMails
Set olApp = CreateObject("Outlook.Application")
Set olNs = olApp.GetNamespace("MAPI")
Set olFldr = olNs.GetDefaultFolder(olFolderSentMail)
Set olMails = olFldr.Items
For Each olMail In olMails
olMail.ReplyAll
olMail.Importance = 2
olMail.Subject = "RE: 2ND " & olMail.Subject
olMail.Send
Next olMail
End Function
However, for some strange reason, this function sends only half of all emails in designated folder. If there are 9 emails, the function sends out 5 (4 left), then if I run another iteration, the function sends out 2, and so on...
If I change olMail.Send to olMail.Display, then the function displays all emails in pop-up frames.
Has any one encountered this issue or know what's the reason behind it?
Thanks.

For starters, I don't understand why you are not using the MailItem object returned from the ReplyAll method to set the properties and call .Send on that object and not the copy of the sent item represented by your olMail variable.
Otherwise I suspect the collection of items is changing. Change the For Each to a For with a reverse counter loop and the weirdness should go away.

Related

Batch "Copy to My Calendar" VBA Macro for Outlook

I have approximately 14,000 Outlook invitations in a Outlook folder that was generated from a legal discovery. Counsel would like all these imported into a normal "Calendar View" (turning the invite into an actual calendar entry). The two solutions I came up with is either require forwarding the invitation to a separate account (and auto accept) or use the Outlook "Copy to My Calendar" option which is what I'm hoping to accomplish.
Copied below is code I found to FORWARD all selected invitations in the Outlook folder. My concern with the forward is that it will notify the meeting organizer which we certainly don't want. I'm hoping someone can suggested a modification so this triggers "Copy to My Calendar" instead. Any help or guidance would greatly be appreciated!
Sub BatchForwardMultipleCalendarItems()
Dim objSelection As Outlook.Selection
Dim i As Integer
Dim objCalendarItem As Outlook.AppointmentItem
Dim objMail As Outlook.MailItem
Set objSelection = Outlook.Application.ActiveExplorer.Selection
For i = objSelection.Count To 1 Step -1
Set objCalendarItem = objSelection.Item(i)
Set objMail = Outlook.Application.CreateItem(olMailItem)
With objMail
.Attachments.Add objCalendarItem
'Change the recipient's email address
.Recipients.Add ("shelly#datanumen.com")
.Recipients.ResolveAll
.Subject = objCalendarItem.Subject
.Body = "Type body here ...."
.Send
End With
Next i
End Sub
Instead of creating a new mail item in the code and just sending it out with an attached appointment item:
Set objMail = Outlook.Application.CreateItem(olMailItem)
You can use the AppointmentItem.ForwardAsVcal method which forwards the AppointmentItem as a vCal (virtual calendar item). A MailItem object that represents the new mail item to which the calendar information is attached is returned back.
There is no other way available in the Outlook object model.

Send an email with a blank subject

I am a professor interacting with students who do not respond to emails, but who do respond to text messages. So, I am writing an Outlook userform to generate text messages that are sent by Outlook to students' cell phones, e.g., by using email addresses that target the student's cell phone text message service like this: 5405551212#mms.att.net
The problem I am running into is that I don't want to have a Subject for these text messages because that Subject is added as the first line of each text sent to the student and is confusing and looks weird, but, the VBA code olMail.Send will throw this error when the Subject is blank: "Run-time error '-2147467259 (80004005)': Outlook does not recognize one or more names." The names for olMail.To and olMail.CC are fine and the error goes away when I add a non-blank Subject.
Is there a way to programmatically force Outlook to send the email with a blank subject? I have not been able to find a solution searching online other than to make the subject " " (a space)--but that is not an ideal solution because it still adds a "blank" line at the top of each text message because of the space.
I could probably use olMail.Display and then use SendKeys to send the email and answer "Yes" when I am asked if I want to send the email without a subject, but that is clunky.
How can I skip the error and send the email without a subject using VBA?
EDIT:
Here's the code that I was using to add recipients to the mailitem:
Dim olApp As Outlook.Application
Dim olMail As MailItem
olMail.To = Me.tbxEmailAddress 'this would be something like 5405551212#mms.att.net
olMail.CC = "someemail#notmail.com" 'this would be my own email address
olMail.Subject = "" 'blank subject
olMail.Body = Replace(Me.tbxTexts, vbCrLf, "") 'remove extra hard returns
olMail.Send 'this would throw the error mentioned above,
'but if I changed olMail.Subject = "" to
'olMail.Subject = "This is the subject" then no error would occur
Using #Eugene Astafiev's information below, I cobbled together a working solution like this:
Dim myRecipients As Outlook.Recipients
Dim myRecipient As Outlook.Recipient
Dim olApp As Outlook.Application
Dim olMail As MailItem
Set olApp = Outlook.Application
olMail.Subject = "" 'blank subject
olMail.Body = Replace(Me.tbxTexts, vbCrLf, "") 'remove extra hard returns
Set myRecipient = olMail.Recipients.Add(tbxEmailAddress)
myRecipient.Type = olTo 'Type is: olBCC, olCC, olOriginator, or olTo
Set myRecipient = olMail.Recipients.Add("someemail#notmail.com")
myRecipient.Type = olBCC
Set myRecipients = olMail.Recipients
If Not myRecipients.ResolveAll Then
For Each myRecipient In myRecipients
If Not myRecipient.Resolved Then
MsgBox "Could not resolve: " & myRecipient.Name
End If
Next
End If
olMail.Send 'no error now!
Interestingly, no email address using the myRecipients collection ever reported being unable to be resolved. However, when I tried to resolve the individual myRecipient object/item using myRecipient.Resolve then the text message email address (e.g., 5405551212#mms.att.net) would fail to resolve but my own email address would resolve fine.
Maybe this has something to do with 5405551212#mms.att.net not being an address in my Address Book or Contacts?
At any rate, it does send now. (Note: prior to using the myRecipients.ResolveAll, I did succeed in getting the code I originally had to work by using olMail.Display and then olMail.Send and then using SendKeys "%s" twice--the first time to "click" the Send button and the second time to "click" the "Send Anyway" button when Outlook complained there was no subject. But, clearly the VBA code approach is far superior.)
Thanks to everyone for you help!
Outlook doesn't require setting up the Subject line before submitting items. Use the Recipients.ResolveAll method which attempts to resolve all the Recipient objects in the Recipients collection against the Address Book.
Sub CheckRecipients()
Dim MyItem As Outlook.MailItem
Dim myRecipients As Outlook.Recipients
Dim myRecipient As Outlook.Recipient
Set myItem = Application.CreateItem(olMailItem)
Set myRecipients = myItem.Recipients
myRecipients.Add("Eugene Astafiev")
myRecipients.Add("Nate Sun")
myRecipients.Add("Dan Wilson")
If Not myRecipients.ResolveAll Then
For Each myRecipient In myRecipients
If Not myRecipient.Resolved Then
MsgBox myRecipient.Name
End If
Next
End If
End Sub
You may find the following articles helpful:
How To: Fill TO,CC and BCC fields in Outlook programmatically
How To: Create and send an Outlook message programmatically

Control contents of email address fields

I want to send the body of a Word document as an email from MS Word 2016.
I want the user to select recipients from the address book. I want them to only be put in the BCC field.
How do I monitor the to/from/CC/BCC fields for changes, and then move those changes to BCC?
The documentation indicates the use of Inspectors, but nothing specific about accessing the contents of these fields.
I have two approaches:
open a new Outlook mail item, load the contents of the Word file to it, and then try to monitor the fields that way.
send directly from Word using the Quick Access Toolbar option "Send to Mail Recipient".
I don't know if that is an option based on what I was reading and if those fields are accessible via VBA.
Code example of what I have so far:
Sub SendDocumentInMail()
Dim bStarted As Boolean
Dim oOutlookApp As Outlook.Application
Dim oItem As Outlook.MailItem
On Error Resume Next
'Get Outlook if it's running
Set oOutlookApp = GetObject(, "Outlook.Application")
If Err <> 0 Then
'Outlook wasn't running, start it from code
Set oOutlookApp = CreateObject("Outlook.Application")
bStarted = True
End If
'Create a new mailitem
Set oItem = oOutlookApp.CreateItem(olMailItem)
With oItem
'Set the recipient for the new email
.To = "recipient#mail.com"
'Set the recipient for a copy
.CC = "recipient2#mail.com"
'Set the subject
.Subject = "New subject"
'The content of the document is used as the body for the email
.Body = ActiveDocument.Content
.Send
End With
If bStarted Then
'If we started Outlook from code, then close it
oOutlookApp.Quit
End If
'Clean up
Set oItem = Nothing
Set oOutlookApp = Nothing
End Sub
It seems you are interested in the SelectNamesDialog object which displays the Select Names dialog box for the user to select entries from one or more address lists, and returns the selected entries in the collection object specified by the property SelectNamesDialog.Recipients.
The dialog box displayed by SelectNamesDialog.Display is similar to the Select Names dialog box in the Outlook user interface. It observes the size and position settings of the built-in Select Names dialog box. However, its default state does not show Message Recipients above the To, Cc, and Bcc edit boxes.
The following code sample shows how to create a mail item, allow the user to select recipients from the Exchange Global Address List in the Select Names dialog box, and if the user has selected recipients that can be completely resolved, then send the mail item.
Sub SelectRecipients()
Dim oMsg As MailItem
Set oMsg = Application.CreateItem(olMailItem)
Dim oDialog As SelectNamesDialog
Set oDialog = Application.Session.GetSelectNamesDialog
With oDialog
.InitialAddressList = _
Application.Session.GetGlobalAddressList
.Recipients = oMsg.Recipients
If .Display Then
'Recipients Resolved
oMsg.Subject = "Hello"
oMsg.Send
End If
End With
End Sub

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.

Sending email through MS Access VBA / Outlook, choosing sending profile

I am looking at this snippet of code from another question here (MS Access VBA): https://stackoverflow.com/a/17975507/1085885
Right now this code only works when I run it while Outlook is open. Is there any way for this code to "open Outlook" and then run all the sending code?
Secondly, how can I choose which Outlook profile to send from? I have access to a couple different profiles and it's sending from my main top inbox but I want it to come from my second inbox.
You need to log to the specified profile (as shown in "Control Panel | Mail | Show Profiles", if that is what you mean by "profile"). After creating an instance of the Outlook application
Set oApp = CreateObject("Outlook.application")
add something like the following:
set oNS = oApp.GetNamespace.Logon
oNS.Logon("MyProfileName")
Note if Outlook is already running, Logon will do nothing. You will need to use Extended MAPI (C++ or Delphi or a MAPI wrapper like Redemption (I am its author, use RDOSession.Logon) to log to a specified profile.
If by "profile" you actually mean a different account in the same profile in Outlook, you can set the MailItem.SendUsingAccount property to specify a particular account.
If you are sending from an Exchange mailbox, and you need to set a different sender, set the MailItem.SentOnBehalfOfName property to the name of the user on whose behalf you are sending (assuming you have the right to send on behalf of that user).
Try it this way.
Private Sub Command1_Click()
Dim bStarted As Boolean
Dim oOutlookApp As Outlook.Application
Dim oItem As Outlook.MailItem
On Error Resume Next
'Get Outlook if it's running
Set oOutlookApp = GetObject(, "Outlook.Application")
If Err <> 0 Then
'Outlook wasn't running, start it from code
Set oOutlookApp = CreateObject("Outlook.Application")
bStarted = True
End If
'Create a new mailitem
Set oItem = oOutlookApp.CreateItem(olMailItem)
With oItem
'Set the recipient for the new email
.To = "receiver#gmail.com"
.Send
End With
If bStarted Then
' 'If we started Outlook from code, then close it
oOutlookApp.Quit
End If
'Clean up
Set oItem = Nothing
Set oOutlookApp = Nothing
End Sub