Trying to warn if sending from a personal email account - vba

I'm trying to prompt if sending from a personal account in Outlook.
I have the following which works 90% of the time, however sometimes it errors with the following:
You cannot send an item that is already in the process of being sent
Code for reference:
Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)
Dim Send_Address As String
Dim Prompt As String
' Check Send_From name
Send_Address = Item.SendUsingAccount
Select Case Send_Address
Case "example#domain.uk"
Case Else
Prompt = "You are currently sending this email from " & Send_Address & "" & vbNewLine & "Do you want to proceed?"
If MsgBox(Prompt, vbYesNo + vbQuestion + vbMsgBoxSetForeground, "Check Address") = vbNo Then
Cancel = True
End If
End Select
End Sub

You can't cast an instance of the Account class to a string:
Dim Send_Address As String
Dim Prompt As String
' Check Send_From name
Send_Address = Item.SendUsingAccount
The SendUsingAccount property returns or sets an Account object that represents the account under which the MailItem is to be sent. The SendUsingAccount property can be used to specify the account that should be used to send the MailItem when the Send method is called. This property returns Null (Nothing in Visual Basic) if the account specified for the MailItem no longer exists. For example, here is a sample use case:
Sub SendUsingAccount()
Dim oAccount As Outlook.account
For Each oAccount In Application.Session.Accounts
If oAccount.AccountType = olPop3 Then
Dim oMail As Outlook.MailItem
Set oMail = Application.CreateItem(olMailItem)
oMail.Subject = "Sent using POP3 Account"
oMail.Recipients.Add ("someone#example.com")
oMail.Recipients.ResolveAll
Set oMail.SendUsingAccount = oAccount
oMail.Send
End If
Next
End Sub
So, to check the SMTP address you need to use the following code:
Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)
Dim account as Outlook.Account
Dim Send_Address As String
Dim Prompt As String
' Check Send_From name
Set account = Item.SendUsingAccount
If Not account Is Nothing then
Send_Address = account.SmtpAddress
Select Case Send_Address
Case "example#domain.uk"
Case Else
Prompt = "You are currently sending this email from " & Send_Address & "" & vbNewLine & "Do you want to proceed?"
If MsgBox(Prompt, vbYesNo + vbQuestion + vbMsgBoxSetForeground, "Check Address") = vbNo Then
Cancel = True
End If
End Select
End If
End Sub

Related

How to insert HTML elements in email body

I want to apply HTML when a user prepares email with a default template.
I got some basic code online:
Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)
On Error Resume Next
If InStr(LCase(Item.To), "xxx#gmail.com") Then
prompt$ = "Are You Sure want to send this email to " & Item.To& " ?"
If MsgBox(prompt$, vbYesNo + vbQuestion + vbMsgBoxSetForeground, "Check Address") = vbNo Then
Cancel = True
Dim objOutlookMsg As Outlook.MailItem
Set objOutlookMsg = Outlook.Application.CreateItem(olMailItem)
objOutlookMsg.HTMLBody = "<html><body><strong>HELLO OUTLOOK</strong></body></html>"
objOutlookMsg.Display
End If
End If
End Sub
When I send, a new message window opens.
I want that HTML to present in the same window, not a new window.
The Item.To Property Returns String list of display names, what you need it Recipient.Address Property which will Return a String representing the email address of the Recipient.
Also check If Item.Class <> olMail if not then Exit Sub
Full Example
Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)
If Item.Class <> olMail Then Exit Sub
Dim Rcpt As Recipient
Dim Prompt As String
Prompt = "Are You Sure want to send this email to " & Item.To & " ?"
For Each Rcpt In Item.Recipients
If InStr(1, Rcpt.AddressEntry, "TEST#gmail.com", vbTextCompare) Then
If MsgBox(Prompt, vbYesNo + vbQuestion + vbMsgBoxSetForeground, _
"Check Address ") = vbNo Then
Cancel = True
Exit Sub
End If
Item.HTMLBody = "<html><body><strong>HELLO OUTLOOK</strong></body></html>" _
& Item.HTMLBody
End If
Next
End Sub
Updated per comments
Simply remove if MsgBox end if block of code
Example
Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)
If Item.Class <> olMail Then Exit Sub
Dim Rcpt As Recipient
For Each Rcpt In Item.Recipients
If InStr(1, Rcpt.AddressEntry, "TEST#gmail.com", vbTextCompare) Then
Item.HTMLBody = "<html><body><strong>HELLO OUTLOOK</strong></body></html>" _
& Item.HTMLBody
End If
Next
End Sub
If you want to modify the HTML body of the message begin sent (it is passed as the Item parameter to your event handler), why are you creating a new message instead of modifying the existing message? Set HTMLBody property on the Item object.

Outlook Macro to match domain name from a list in excel

I need a macro which can match domain name of the email ids in TO and CC from a list of emails(preferably from excel) and if any of the email address does not match, it should throw a pop-up asking if the user wants to continue and if yes then the mail should be sent as it is and a email id should be added in BCC.
Please find the sample code, it works but I also want to compare the domain name as a sub-string in the subject.
Ex: The if the subject line is "ABC Report- Company1- Jan-2 and it is sent to a1#company1.com, a2#compay2.com then it should prompt that the a2#company2.com is an unauthorized email and ask if still the user want to proceed, if Yes it should copy admin#mycompany.com in BCC and delay the mail by 5mins.
Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)
Dim recips As Outlook.Recipients
Dim recip As Outlook.Recipient
Dim pa As Outlook.PropertyAccessor
Dim prompt As String
Dim strMsg As String
Dim Address As String
Dim lLen
Dim strSubject As String
Const PR_SMTP_ADDRESS As String = "http://schemas.microsoft.com/mapi/proptag/0x39FE001E"
strSubject = Item.Subject
If strSubject Like "*ACB Report*" Or strSubject Like "*XYZ Report*" Then
   
Set recips = Item.Recipients
For Each recip In recips
Set pa = recip.PropertyAccessor
 Address = LCase(pa.GetProperty(PR_SMTP_ADDRESS))
lLen = Len(Address) - InStrRev(Address, "#")
Select Case Right(Address, lLen)
    Case "cdolive.com", "gmail.com", "slipstick.com", "outlookmvp.com"
        
    Case Else ' remove case else line to be warned when sending to the addresses
     strMsg = strMsg & " " & Address & vbNewLine
End Select
Next
If strMsg <> "" Then
prompt = "This email will be sent outside of the company to:" & vbNewLine & strMsg & vbNewLine & "Please check recipient address." & vbNewLine & vbNewLine & "Do you still wish to send?"
If MsgBox(prompt, vbYesNo + vbExclamation + vbMsgBoxSetForeground, "Check Address") = vbNo Then
Cancel = True
End If
End If
End If
End Sub
Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)
Dim recips As Outlook.Recipients
Dim recip As Outlook.Recipient
Dim pa As Outlook.PropertyAccessor
Dim prompt As String
Dim strMsg As String
Dim Address As String
Dim lLen
Dim strSubject As String
Const PR_SMTP_ADDRESS As String = "http://schemas.microsoft.com/mapi/proptag/0x39FE001E"
strSubject = Item.subject
If strSubject Like "*ABC Report*" Or strSubject Like "*XYZ Report*" Then
Set recips = Item.Recipients
For Each recip In recips
If recip.Type <> olBCC Then
Set pa = recip.PropertyAccessor
Address = LCase(pa.GetProperty(PR_SMTP_ADDRESS))
'rlen = Len(Address) - InStrRev(Address, "#")
'If strSubject Like "*rlen*" Then
lLen = Len(Address) - InStrRev(Address, "#")
'Select Case Left(Address, rlen)
'Case "acceture", "slipstick"
'Case Else
'strMsg = strMsg & " " & Address & vbNewLine
'End Select
'Next
Dim SendMail As Boolean
Select Case Right(Address, lLen)
Case "cdolive.com", "slipstick.com", "outlookmvp.com", "accenture.com"
' "select case" is doing nothing in this case
SendMail = True
Case Else ' remove case else line to be warned when sending to the addresses
strMsg = strMsg & " " & Address & vbNewLine
End Select
If strMsg <> "" And Not SubjectContainsEmailDomain(strSubject, Address) Then
prompt = "The system has detected that you are sending this email to some unauthorized user:" & vbNewLine & strMsg & vbNewLine & "Please check recipient address." & vbNewLine & vbNewLine & "Do you still wish to send?"
If MsgBox(prompt, vbYesNo + vbExclamation + vbMsgBoxSetForeground, "Check Address") = vbNo Then
Cancel = True
Else
' add BCC
Dim objRecip As Recipient
Set objRecip = Item.Recipients.Add("myid#gmail.com")
objRecip.Type = olBCC
objRecip.Resolve
'MailItem.DeferredDeliveryTime = DateAdd("n", 90, Now)
End If
End If
' Cancel if not in "cdolive.com", "slipstick.com", "outlookmvp.com"
If Not SendMail Then Cancel = True
MsgBox "The entered email address(s) are not aliged to you" & vbNewLine & "Please add the domain name in the code"
'End If
'End If
End If
Next
Last:
End If
End If
End If
End Sub
Function GetDomain(emailAddress As String) As String
Dim arr As Variant
arr = Split(emailAddress, "#")
GetDomain = Left(arr(1), InStrRev(arr(1), ".") - 1)
End Function
Function SubjectContainsEmailDomain(subject As String, email As String) As Boolean
Dim domain As String
domain = GetDomain(email)
Dim index As Integer
SubjectContainsEmailDomain = InStr(LCase(subject), LCase(domain))
End Function
The next to last part of an email address is the Second Level Domain (2LD).
This seems to be finding Recipient2LD that is different from the Subject Company.
The Subject seems to be free form typing by users, and I have no idea how to parse the SubjectCompany out of the Subject line, but if you could then this could be added after EndSelect and before Next.
Dim RecipDomainParts() As String
RecipDomainParts = Split(Right(Address, lLen), ".")
Dim Recip2LD As String ' Recipient Second Level Domain
Recip2LD = DomainParts(UBound(DomainParts) - 1)
' I have no idea how to parse the SubjectCompany out of the Subject line
If Recip2LD <> SubjectCompany Then
strMsg = strMsg & " " & Address & vbNewLine
End If
->>added 9/2/18
you need to decide yourself the general outline of your process: whether to possibly have an error message for each Recipient for each problem (List or Subject) or to combine into one message for a Recipient, while doing each Recipient, or append each msg into one message at the end of all Recipients... Then follow your outline. Work at refining the outline first, then write the code to match.
It may be good to make sub for "Recip_in_List" and make a sub for "RecipDomain_in_Subject" after you revise the outline.
BCC probably should not be skipped, as user might try to put an email there.
Your xyz#qwerty.com should be in the List.
variable SendMail cannot be set to True because it would wipe out False that had been set on prior Recipient. By doing Exit Sub when vbNo you eliminate this boolean.
Set Delay = 0min
For each Recip
If Recip not in List
Popup to user
If vbNo then Cancel=True and exit without send
Else add BCC of xyz#qwerty.com if not there
endif
endif
If RecipDomain not in Subject
Popup to user
If vbNo then Cancel=True and exit without send
Else add BCC of admin#qwerty.com if not there
set Delay = 5min
endif
endif
Next Recip
SEND with Delay

VBA: Find whether there is common pattern between the email subject and attachment name

I want to validate that the outgoing email is correctly attached with a correct file. The email subject contains a code. The attachment filename is automatically generated with a code and attached manually to the email. The VBA is to check whether the email subject contains a common pattern in the filename of the attachment.
The code is like H??#######, i.e. it must start with "H", followed with 2 letters, and then 7 digits.
If both the email subject and filename contain the same code, the email is allowed to send, otherwise it should warn. For example:
Subject: Urgent Chapter 10 - HCX1234567 updated on 12 Dec 2015
Filename: HCX1234567_ABCCh10_20151212_0408
This email is allowed.
Is it possible to do such validation before sending?
Here is my attempt:
Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)
'Create Geoff Lai on 14 March 2016
Dim recips As Outlook.Recipients
Dim recip As Outlook.Recipient
Dim pa As Outlook.PropertyAccessor
Dim prompt As String
Dim strMsg As String
Dim mailContent As String
Dim jobCode As String
Dim attachName As String
Dim pos As Integer
Dim jcodepos As Integer
Const PR_SMTP_ADDRESS As String = "http://schemas.microsoft.com/mapi/proptag/0x39FE001E"
attachName = Item.Attachments.Item(1).FileName
mailContent = Item.Body + Item.Subject ' Get a copy of all the e-mail body text and subject text to search.
mailContent = LCase(mailContent) ' Make whole string lowercase for easier searching.
Set recips = Item.Recipients
For Each recip In recips 'Record email addressees if send to external domain
Set pa = recip.PropertyAccessor
If InStr(LCase(pa.GetProperty(PR_SMTP_ADDRESS)), "#mydomain.com") = 0 Then
strMsg = strMsg & " " & pa.GetProperty(PR_SMTP_ADDRESS) & vbNewLine
End If
Next
If strMsg <> "" Then
If (Item.Attachments.Count = 0) Then ' Check attachment
If InStr(1, mailContent, "attach") > 0 Then
pos = 1
ElseIf InStr(1, mailContent, "Attach") > 0 Then
pos = 1
ElseIf InStr(1, mailContent, "enclose") > 0 Then
pos = 1
ElseIf InStr(1, mailContent, "Enclose") > 0 Then
pos = 1
Else: pos = 0
End If
End If
If (pos > 0) Then 'If there is no attachment:
If MsgBox("With the word attach or enclose, attachment should be found in this email" & vbNewLine & "Please Confirm.", vbYesNo + vbCritical + vbMsgBoxSetForeground, "Missing Attachment") = vbYes Then
prompt = "This email will be sent outside of mydomain.com to:" & vbNewLine & strMsg & "Do you want to proceed?"
If MsgBox(prompt, vbYesNo + vbExclamation + vbMsgBoxSetForeground, "Check Address") = vbNo Then
Cancel = True
Exit Sub
Else
Exit Sub
End If
Else
Cancel = True 'Stop sending
End If
End If
If (Item.Attachments.Count > 0) Then ' Validate attachment and subject
jcodepos = InStr(1, attachName, "H??#######", 0) ' Get job code position
jobCode = Mid(attachName, jcodepos, 10) ' Get job code
If (InStr(1, Item.Subject, jobCode, 0) = 0) Then ' If no common code between subject and attachment
If MsgBox("There is no common job code between the email subject and the filename of the attachment." & vbNewLine & "Do you want to proceed?", _
vbYesNo + vbCritical + vbMsgBoxSetForeground, "Wrong Attachment?") = vbNo Then
Cancel = True
Exit Sub
Else
Exit Sub
End If
ElseIf MsgBox("Common job code " & jobCode & " is found in the email subject and the filename of the attachment" & prompt, _
vbYesNo + vbQuestion + vbMsgBoxSetForeground, "Confirm Job Code") = vbNo Then ' If common code is found
Cancel = True
Exit Sub
Else
Exit Sub
End If
End If
End If
End Sub
However, I get an error at jobCode = Mid(attachName, jcodepos, 10), which is:
Run-time error '5' Invalid procedure call or argument
Application_ItemSend, the usual way, in ThisOutlookModule. How can I automatically run a macro when an email is sent in Outlook?
In the VB editor set the reference to Regular Expressions.
Similar to the code in the Question part of Regular Expression Rules in Outlook 2007?. Check RegEx.Pattern = "(H[A-Z]{2}[0-9]{7})" against the filename. Continue with RegEx or InStr to verify the subject includes the filename match.
Since you thinking about using VBA I would assume that you are using Outlook as your email client. If so, please add this to your question and the tags. With this assumption the answer is that it depends:
If Outlook is actually used to send the email then it can be done. The following Q&A is probably a good starting point.
how to check details before sending mails in outlook using macros?
Yet, the above technique will not work if the email is created with File | Send commands in Office programs or similar commands in Windows Explorer or other programs.
Finally, I have figured it out, Thanks for the advices!
Here is my workout.
Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)
Dim recips As Outlook.Recipients
Dim recip As Outlook.Recipient
Dim pa As Outlook.PropertyAccessor
Dim regex As Object, codeInSubject As Object, codeInAttach As Object
Dim matchSbjtCode As String, matchAttchcode As String
Dim prompt As String
Dim strMsg As String
Dim mailContent As String
Dim attachName As String
Dim pos As Integer
Const PR_SMTP_ADDRESS As String = "http://schemas.microsoft.com/mapi/proptag/0x39FE001E"
Set regex = CreateObject("vbScript.regExp")
With regex
.Pattern = "[H][ACDILNOPQTUVW][BCGJMOPRSTWY][1-9][0-9]{6}" ' Set regular expression pattern
.Global = False ' Check the first instance only
End With
attachName = Item.Attachments.Item(1).FileName
mailContent = Item.Body + Item.Subject ' Get a copy of all the e-mail body text and subject text to search.
mailContent = LCase(mailContent) ' Make whole string lowercase for easier searching.
Set recips = Item.Recipients
For Each recip In recips 'Record email addressees if send to external domain
Set pa = recip.PropertyAccessor
If InStr(LCase(pa.GetProperty(PR_SMTP_ADDRESS)), "#mydomain.com") = 0 Then
strMsg = strMsg & " " & pa.GetProperty(PR_SMTP_ADDRESS) & vbNewLine
End If
Next
prompt = "This email will be sent outside of mydomain.com to:" & vbNewLine & strMsg & "Do you want to proceed?"
If strMsg <> "" Then
If (Item.Attachments.Count = 0) Then ' Check attachment
If InStr(1, mailContent, "attach") > 0 Then
pos = 1
ElseIf InStr(1, mailContent, "enclose") > 0 Then
Else: pos = 0
End If
End If
If (pos > 0) Then 'If there is no attachment:
If MsgBox("With the word 'attach' or 'enclose', attachment should be found in this email" & vbNewLine & _
"Please Confirm.", vbYesNo + vbCritical + vbMsgBoxSetForeground, "Missing Attachment") = vbYes Then ' Prompt to check
If MsgBox(prompt, vbYesNo + vbExclamation + vbMsgBoxSetForeground, "Check Address") = vbNo Then
Cancel = True
Exit Sub
Else
Exit Sub
End If
Else
Cancel = True 'Stop sending
End If
End If
If (Item.Attachments.Count > 0) Then ' Validate attachment and subject
If regex.test(Item.Subject) And regex.test(attachName) Then ' Test the job codes in the email subject and attachment filename
Set codeInSubject = regex.Execute(Item.Subject)
Set codeInAttach = regex.Execute(attachName)
If StrComp(codeInSubject(0), codeInAttach(0)) = 0 Then ' Compare the codes found
If MsgBox("Common job code """ & codeInAttach(0) & """ is found in the email subject and the filename of the attachment. " & vbNewLine & prompt, _
vbYesNo + vbQuestion + vbMsgBoxSetForeground, "Confirm Job Code") = vbNo Then ' If found, confirm to send
Cancel = True
Else: Exit Sub
End If
ElseIf MsgBox("There is no common job code between the email subject and the filename of the attachment." & vbNewLine & _
"Do you want to DISCARD?", vbYesNo + vbCritical + vbMsgBoxSetForeground, "Wrong Attachment?") = vbYes Then ' if not found, discard
Cancel = True
Else: Exit Sub
End If
End If
End If
End If
End Sub

Outlook Macro to add email to Bcc and send it

I have little VBA experience so I found a few post that were kinda like what I want but I can't seem to make them work.
I would like a to add an email address to outlook as a Bcc and send it.
It goes under thisOutlookSession
Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)
Dim olRecip As Recipient
Dim olMsg As String
Dim res As Integer
Dim olBcc As String
On Error Resume Next
'// set email address here
olBcc = "Address#domain.com"
Set olRecip = Item.Recipients.Add(olBcc)
olRecip.Type = olBcc
If Not olRecip.Resolve Then
olMsg = "Could not resolve Bcc recipient. " & _
"Do you still want to send?"
res = MsgBox(olMsg, vbYesNo + vbDefaultButton1, _
"Could Not Resolve Bcc Recipient")
If res = vbNo Then
Cancel = True
End If
End If
Set olRecip = Nothing
End Sub

Outlook VBA to verify recipient

What is the best way to check for multiple black-list email addresses before sending?
I have several email addresses I am not allowed to send information to as part of a project. I want Outlook to check for any of the black-list email addresses and notify me if they are included before sending. Below is the code I found to modify
For example, my black-list includes: "bad#address.com", "worst#address.com", "evil#address.com"
What is the best way to put these addresses into the code below, would be good for it to be in a way that allows for changing the addresses in the black-list easily?
So here is the latest version of my code with your suggestions. Unfortunately it lets me send the emails to the addresses on the Checklist. Any suggestions?
Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)
Dim Recipients As Outlook.Recipients
Dim recip As Outlook.Recipient
Dim i
Dim prompt As String
On Error Resume Next
' use lower case for the address
' LCase converts all addresses in the To field to lower case
Checklist = "bad#address.com" & _
"worst#address.com" & _
"evil#address.com" '// , _ and so on
Set Recipients = Item.Recipients
For i = Recipients.Count To 1 Step -1
Set recip = Recipients.Item(i)
If InStr(LCase(recip), LCase(Checklist)) Then
prompt$ = "You sending this to this to " & Item.To & ". Are you sure you want to send it?"
If MsgBox(prompt$, vbYesNo + vbQuestion + vbMsgBoxSetForeground, "Check Address") = vbNo Then
Cancel = True
End If
End If
Next i
End Sub
Create a procedure level variable CheckList which is the list of csv of black listed emails. you can initialise this in the procedure as a hard assignment or dynamically retrieve from other data sources for e.g. sql server
Dim lbadFound As Boolean
dim badAddresses as string
lbadFound = False
CheckList = "bad#address.com," & _
"worst#address.com," & _
"evil#address.com" '// , _ and so on
Set Recipients = Item.Recipients
For i = Recipients.Count To 1 Step -1
Set recip = Recipients.Item(i)
If instr(1,lcase(CheckList), LCase(recip)) >=1 Then
lbadFound = true
badAddresses = badAddresses & recip & & vbcrlf
End If
Next i
If lbadFound Then
prompt$ = "You sending this mail to one or more black listed email address(es)" & badAddresses & vbcrlf & " Are you sure you want to send it?"
If MsgBox(prompt$, vbYesNo + vbQuestion + vbMsgBoxSetForeground, "Check Address") = vbNo Then
Cancel = True
End If
End If