Outlook Add-in Sender/TO/CC/BCC issue VB.net - vb.net

I have having some problems with trying to get the list of other email address within an email. Currently it gets the SenderName just fine but once it moves on to the To it seems to still have the SenderName as the same over and over again.
If _mailItem.SenderName IsNot Nothing Then
Dim tmpResult() As String = _mailItem.SenderName.ToString.Split(";")
For Each name In tmpResult
result = name.Split(",")
If result.Length > 1 Then
employeeAlreadyThere = EIG.FindContactEmailByName(GetSenderSMTPAddress(_mailItem).Trim)
If employeeAlreadyThere = False Then
Call EIG.Search(name.ToString)
End If
End If
Next
End If
Now that works just fine as i said for the SenderName. However, the below code is what comes after the above code:
If _mailItem.To IsNot Nothing Then
Dim tmpResult() As String = _mailItem.To.ToString.Split(";")
For Each name In tmpResult
result = name.Split(",")
If result.Length > 1 Then
employeeAlreadyThere = EIG.FindContactEmailByName(GetSenderSMTPAddress(_mailItem).Trim)
If employeeAlreadyThere = False Then
Call EIG.Search(name.ToString)
End If
Else
EIG.lastFirstName = name.Trim().ToString
EIG.emailAddress = EIG.lastFirstName.Replace("-", "_").Replace("/", "").Replace("\", "").Replace(" ", "_").Trim() & "#zzzz.com" 'DL-I/S etwBusiness => DL#zzzz.com
Call EIG.saveImage()
End If
Next
End If
The GetSenderSMTPAddress(_mailItem) code is this:
Private Function GetSenderSMTPAddress(ByVal mail As Outlook.MailItem) As String
Dim PR_SMTP_ADDRESS As String = "http://schemas.microsoft.com/mapi/proptag/0x39FE001E"
If mail Is Nothing Then
Throw New ArgumentNullException()
End If
If mail.SenderEmailType = "EX" Then
Dim mail_sender As Outlook.AddressEntry = mail.Sender
If mail_sender IsNot Nothing Then
If mail_sender.AddressEntryUserType = Outlook.OlAddressEntryUserType.olExchangeUserAddressEntry OrElse mail_sender.AddressEntryUserType = Outlook.OlAddressEntryUserType.olExchangeRemoteUserAddressEntry Then
Dim exchUser As Outlook.ExchangeUser = mail_sender.GetExchangeUser()
If exchUser IsNot Nothing Then
Return exchUser.PrimarySmtpAddress
Else
Return Nothing
End If
Else
Return TryCast(mail_sender.PropertyAccessor.GetProperty(PR_SMTP_ADDRESS), String)
End If
Else
Return Nothing
End If
Else
Return mail.SenderEmailAddress
End If
End Function
I'm passing a Outlook.MailItem and i know that will always produce the SenderName but this is where I am unsure how to go about getting the TO, CC & BCC.
I've tried:
GetSenderSMTPAddress(_mailItem.To)
and that throws a warning of:
Warning 1 Runtime errors might occur when converting 'String' to
'Microsoft.Office.Interop.Outlook.MailItem'.
So any tips on fixing this would be great!

All the recipients are stored in MailItem.Recipients as Recipient objects. You will need to access Recipient.AddressEntry in order to get SMTP addresses for Exchange recipients. The To, Cc and Bcc fields are only helpful for getting display names.
Also: there's no need to do a Split on SenderName; it'll always be one email address or display name.

Related

How to loop through text boxes and verify if there are duplicate values?

I'm trying to setup a function that sends a mail to a defined list of recipients.
Each recipient is fetched from a textbox. The problem is that I want to identify if there are any duplicate values and exclude them when sending the email.
As an example, if textbox1 has the same value as textbox2, don't include textbox1 value in the recipients list.
I've tried with the following sub
Private Sub CheckDuplicates()
Dim x As Long
Dim y As Long
Dim User() As TextBox = {Mail_user1, Mail_user2, Mail_user3, Mail_user4, Mail_user5, Mail_user6, Mail_user7, Mail_user8, Mail_user9, Mail_user10, Mail_user11, Mail_user12, Mail_user13, Mail_user14, Mail_user15, Mail_user16, Mail_user17, Mail_user18, Mail_user19, Mail_user20, Mail_user21, Mail_user22, Mail_user23, Mail_user24, Mail_user25, Mail_user26, Mail_user27, Mail_user28, Mail_user29, Mail_user30}
For x = 1 To 30 - 1
For y = x + 1 To 30
If User(x).Text = User(y).Text Then
User(y).Text = ""
End If
Next
Next
End Sub
The issue is that I get the following error when I want to send the mail:
Index was outside the bounds of the array.
And the mail sub looks like this:
Public Function AddRecipients(mail As outlook.MailItem) As Boolean
Dim retValue As Boolean = False
Dim recipients As outlook.Recipients = Nothing
Dim recipientTo As outlook.Recipient = Nothing
Dim recipientCC As outlook.Recipient = Nothing
Dim recipientBCC As outlook.Recipient = Nothing
Try
recipients = mail.Recipients
' check if there are any recipients and remove them
While recipients.Count > 0
recipients.Remove(1)
End While
' new recipients list
CheckDuplicates()
'------------------CC section---------------------------
recipientCC = recipients.Add("someemail#test.com")
recipientCC.Type = outlook.OlMailRecipientType.olCC
'hidden recipients section
' recipientBCC = recipients.Add("")
' recipientBCC.Type = outlook.OlMailRecipientType.olBCC
retValue = recipients.ResolveAll()
Catch ex As Exception
System.Windows.Forms.MessageBox.Show(ex.Message)
Finally
If Not IsNothing(recipientBCC) Then Marshal.ReleaseComObject(recipientBCC)
If Not IsNothing(recipientCC) Then Marshal.ReleaseComObject(recipientCC)
If Not IsNothing(recipientTo) Then Marshal.ReleaseComObject(recipientTo)
If Not IsNothing(recipients) Then Marshal.ReleaseComObject(recipients)
End Try
Return retValue
End Function
Private Sub MailTime()
Dim OTmail As outlook.MailItem
Dim AppOutlook As New outlook.Application
Try
OTmail = AppOutlook.CreateItem(outlook.OlItemType.olMailItem)
'add users from AddRecipients
AddRecipients(OTmail)
OTmail.Subject = "Test OT mail"
OTmail.Body = "Test Ot mail"
OTmail.BodyFormat = outlook.OlBodyFormat.olFormatHTML
OTmail.Display()
Catch ex As Exception
MessageBox.Show("Could not send, resolve the errors !")
MessageBox.Show(ex.ToString)
Finally
OTmail = Nothing
AppOutlook = Nothing
End Try
End Sub
This will loop through all the TextBoxes and get a Distinct list for you.
Private Function uniqueRecipients() As List(Of String)
Dim recipients As List(Of String) = New List(Of String)
For Each ctrl As TextBox In Me.Controls.OfType(Of TextBox)
recipients.Add(ctrl.Text)
Next
Return recipients.Distinct.ToList
End Function
Private Sub Button26_Click(sender As Object, e As EventArgs) Handles Button26.Click
Try
Dim myRecips As List(Of String) = uniqueRecipients()
Dim oneLine As String = Strings.Join(myRecips.Where(Function(s) Not String.IsNullOrEmpty(s)).ToArray(), ";")
'send mail
Catch ex As Exception
MessageBox.Show(String.Concat("An error occurred: ", ex.Message))
End Try
End Sub
Use right tool type for the job - HashSet(Of String), Enumerable.ToHashSet Method
Private Function GenerateMailRecipientsFrom(textboxes As IEnumerable(Of TextBox)) As String
Dim uniqueRecipients = textboxes.
Select(Function(textbox) textbox.Text).
Where(Function(text) String.IsNullOrWhiteSpace(text) = False).
ToHashSet()
Return String.Join(";", uniqueRecipients)
End Function
HashSet accepts only unique values.
Then use a collection of all textboxes on the form
Dim mailTo As String = GenerateMailRecipientsFrom(Me.Controls.OfType(Of TextBox))
When you have predefined collection of textboxes you can still use the same method
Dim userMailTextBoxes As textBox() = { Mail_user1, Mail_user2, .. }
Dim mailTo As String = GenerateMailRecipientsFrom(userMailTextBoxes)
Nice one ! #Fabrio thanks for the code and explanation. As a side note, I have tried to load the unique values into a listbox and then insert them into outlook email while using this method:
Dim x As Long
For x = 0 To ListBox1.Items.Count - 1
If ListBox1.Items.Item(x) <> "" Then
recipientTo = recipients.Add(ListBox1.Items.Item(x))
recipientTo.Type = outlook.OlMailRecipientType.olTo
End If
Next
Worked like a charm :)

Finding a date in message body and using it to set a reminder in outlook calendar

Currently I have a macro running on all sent items to check that checks to see if I'm sending the e-mail to a particular customer. If I am, then it checks to see if one of the customer’s requirements for all messages is present which is a 'next update due' if it is not it asks if one is required. See below;
Public Sub application_ItemSend(ByVal Item As Object, Cancel As Boolean)
Dim addrType
Dim addr
Dim recip
For Each recip In Item.Recipients
If recip.Type = olTo Then
addrType = recip.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x3002001F")
If addrType = "EX" Then
addr = recip.AddressEntry.GetExchangeUser.PrimarySmtpAddress
Else
addr = recip.Address
End If
If LCase(addr) = "relevantemail1#outlook.com" Or LCase(addr) = "relevantemail2#outlook.com" Then
If InStr(1, Item.Body, LCase("next update due"), vbTextCompare) > 0 Then
Call errhandler
Else
'ask if we've added the date
prompt$ = "You're sending this to company x and have not added a 'next update due' date, do you need to add one?"
If MsgBox(prompt$, vbYesNo + vbQuestion + vbMsgBoxSetForeground, "Check Address") = vbYes Then
Cancel = True
End If
Exit For
End If
End If
End If
Next
End Sub
I am still really getting to grips with the basics of outlook VBA and string functions etc therein. so my question is: can I find the string after the text "next update due:" (ideally I want a formatted date but a string will do for the time being)? Essentially there will always be two delimiters ": " to begin the date and a carriage return to end it. Once I can retrieve it I am able to export the relevant information to an excel document which I will however I am struggling with the initial retrieval of the string/date.
Hopefully you guys can help, more than happy to expand on the above code if needed.
relative simple regex might be used to extract particular date pattern from body
"next update due:(*):"
and your result will be captured in those parenthessis
or with specific date formatting:
"next update due:*(\d\d\/\d\d\/\d\d)*:"
if your date is like 10/01/15
I have made a few changes to your code and hopefully it will get you in the right track.
A few observations to help you with the code.
Always break long code into smaller functions to help you
Always declare variables
Always write comments to help you.
Here is the code I hope it helps
Public Sub application_ItemSend(ByVal Item As Object, Cancel As Boolean)
Dim strAddress As String
Dim oRecipient As Recipient
Dim strNextDueDate As String
For Each oRecipient In Item.Recipients
If oRecipient.Type = olTo Then
' Get the address
strAddress = GetAddress(oRecipient)
' Check the adress for de
If HasToBeChecked(strAddress) Then
If InStr(1, Item.Body, LCase("next update due"), vbTextCompare) > 0 Then
'Get the value for the date.
strNextDueDate = GetStringBetweenStrings(Item.Body, "next update due:", vbCr)
' ------------------------------------------
' The rest of your code here.....
' ------------------------------------------
'Call errhandler
Else
'ask if we've added the date
prompt$ = "You're sending this to company x and have not added a 'next update due' date, do you need to add one?"
If MsgBox(prompt$, vbYesNo + vbQuestion + vbMsgBoxSetForeground, "Check Address") = vbYes Then
Cancel = True
End If
Exit For
End If
End If
End If
Next
End Sub
' Fucntion to check if the address should be chnaged.
' We have it as a separate function so we can add more
' emails if needed.
Function HasToBeChecked(ByVal strAddress As String)
Dim arrAddresses As Variant
Dim i As Long
Dim ret As Boolean
' Load the array of addresses
arrAddresses = Array("relevantemail1#outlook.com", "relevantemail2#outlook.com")
For i = LBound(arrAddresses) To UBound(arrAddresses)
If LCase$(strAddress) = LCase$(arrAddresses(i)) Then
ret = True
Exit For
End If
Next i
'Return the value
HasToBeChecked = ret
End Function
' Function to retrive the address from a recipient object
Function GetAddress(ByRef oRecipient As Recipient) As String
Const strSCHEMA_PROPERTY_TYPE As String = "http://schemas.microsoft.com/mapi/proptag/0x3002001F"
Dim strAddresType As String
Dim ret As String
' Get the address accoring to if it's an excahnge or a regular email
strAddresType = oRecipient.PropertyAccessor.GetProperty(strSCHEMA_PROPERTY_TYPE)
If addrType = "EX" Then
ret = oRecipient.AddressEntry.GetExchangeUser.PrimarySmtpAddress
Else
ret = oRecipient.Address
End If
' Return the value
GetAddress = ret
End Function
' Function to get he string between teo strings
Function GetStringBetweenStrings(ByVal strToCheck As String, _
ByVal strStart As String, _
ByVal strEnd As String) As String
Dim lPosStart As Long
Dim lPostEnd As Long
Dim ret As String
lPosStart = InStr(1, strToCheck, strStart)
If Not lPosStart = 0 Then
lPosStart = lPosStart + Len(strStart) + 1
lPostEnd = InStr(lPosStart, strToCheck, strEnd)
If Not lPostEnd = 0 Then
ret = Mid$(strToCheck, lPosStart, lPostEnd - lPosStart)
End If
End If
' Return the value
GetStringBetweenStrings = ret
End Function
Thanks

Setting ComboBox Selected Value to AD Query

I'm running an AD query to pull selected attributes from a users profile. I'm selecting extensionAttribute3, 4, 5, 6, 7 & 8. Although I can get the result to display as text, I'd like to set the selected vlaue of a combobox to the results.
So extension attribute 3, 5 & 7 = security questions, 4, 6 & 8 are the answers. I have 3 comboboxes, each with a list of 15 possible security questions users can select from, and then provide answers to. I've got my script to update AD with the questions & answers selected. However when I run the application again, I'd like to pull the existing questions from extensionAttribute 3, 5 & 7, as set as the default selected foreach combobox.
Current AD Query Code:
Private Function GetUserProperties()
Dim ADName As String = GetLogonName()
Dim CurrentPIN As String = Nothing
Dim bSuccess As Boolean = False
Dim dirEntry As DirectoryEntry = GetDirectoryEntry()
Dim dirSearcher As DirectorySearcher = New DirectorySearcher(dirEntry)
Dim Q1Value As String = Nothing
dirSearcher.Filter = ("(samAccountName=" & ADName & ")")
dirSearcher.PropertiesToLoad.Add("extensionAttribute3")
dirSearcher.PropertiesToLoad.Add("extensionAttribute4")
dirSearcher.PropertiesToLoad.Add("extensionAttribute5")
dirSearcher.PropertiesToLoad.Add("extensionAttribute6")
dirSearcher.PropertiesToLoad.Add("extensionAttribute7")
dirSearcher.PropertiesToLoad.Add("extensionAttribute8")
dirSearcher.SearchScope = SearchScope.Subtree
Try
Dim dirResult As SearchResult = dirSearcher.FindOne()
bSuccess = Not (dirResult Is Nothing)
If dirResult Is Nothing OrElse dirResult.GetDirectoryEntry.Properties("extensionAttribute3").Value Is Nothing Then
Return "<not set>"
Else
Q1Value = dirResult.GetDirectoryEntry.Properties("extensionAttribute3").Value.ToString
Q1ComboBox.SelectedIndex = Q1Value
End If
Catch ex As Exception
bSuccess = False
MsgBox("No Connection to the domain." & Environment.NewLine & "Please connect to corporate network & try again.", MsgBoxStyle.Critical, "Network Error")
Application.Exit()
End Try
Return False
End Function
It's really hard to format code in comments, i put them here instead.
I'm not VB programmer, may have syntax error.
You don't provide code for extensionAttribute4-8, so it's hard to find what's wrong with them. Do you mean for extensionAttribute4-8, just repeating the if-else block inside the try-catch does not work?
For example, you cannot get value of extensionAttribute4 below?
' code for extensionAttribute3, omitted here
....
' code for extensionAttribute4
If dirResult Is Nothing OrElse dirResult.GetDirectoryEntry.Properties("extensionAttribute4").Value Is Nothing Then
Return "<not set>"
Else
A1Value = dirResult.GetDirectoryEntry.Properties("extensionAttribute4").Value.ToString
A1ComboBox.SelectedIndex = A1Value
End If
' repeat for extensionAttribute5-8
....
For using the attribute already loaded in SearchResult, you already handle the conversion to string problem (mentioned in comment) by calling ToString. You can just do the same thing. But instead of checking dirResult.GetDirectoryEntry.Properties("...").Value Is Nothing, you should check dirResult.Properties("...").Count > 0.
Dim dirResult As SearchResult = dirSearcher.FindOne()
bSuccess = Not (dirResult Is Nothing)
If dirResult Is Nothing OrElse dirResult.Properties("extensionAttribute3").Count <= 0 Then
Return "<not set>"
Else
Q1Value = dirResult.Properties("extensionAttribute3")[0].ToString
Q1ComboBox.SelectedIndex = Q1Value
End If

Why is the IF statement not working? Class object property = Range selection/cell issue

I got a strange issue... my if statement should work but somehow it still doesn't... I can't grasp what is wrong as it seems perfectly right. I can see that the selection is targeting the last row in the A column, and then I'm comparing it to the t_date property in my EURO_USD object which is exactly the same string as in Column("A").End(xlDown), still, it jumps to the else statement(!). Why?
Code
Option Explicit
Private Sub run() ' run the whole operation
Dim HTTP_Req As Object: Set HTTP_Req = New HTTP_Req
Dim EURO_USD As Object: Set EURO_USD = New EURO_USD
Sheets("EURO_USD").Columns("A").End(xlDown).Select
If Selection = EURO_USD.t_date Then
Debug.Print "Date already exist"
Else
Sheets("EURO_USD").Columns("A").End(xlDown).Offset(1, 0) = EURO_USD.t_date
End If
End Sub
EURO_USD Class below
Sub fetch() ' get the function o the ECB URL
Dim xDOM_nodeList As MSXML2.IXMLDOMNodeList
Dim xDom As MSXML2.DOMDocument60
Set xDom = New MSXML2.DOMDocument60
xDom.async = False
xDom.Load "http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml"
Do Until xDom.readyState = READYSTATE_COMPLETE
DoEvents
Loop
xDom.setProperty "SelectionNamespaces", "xmlns:f='http://www.ecb.int/vocabulary/2002-08-01/eurofxref' xmlns:c='http://www.gesmes.org/xml/2002-08-01'"
Set xDOM_nodeList = xDom.SelectNodes("//f:Cube[#currency='USD']")
Curr_ticker = Val(xDOM_nodeList.Item(0).Attributes(1).text)
Set xDOM_nodeList = xDom.SelectNodes("//f:Cube[#time]")
Curr_date = xDOM_nodeList.Item(0).Attributes(0).text
End Sub
Public Property Get ticker()
If Curr_ticker = 0 Then
Call fetch
End If
ticker = Curr_ticker
End Property
Public Property Get t_date()
If Curr_date = "" Then
Call fetch
End If
t_date = Curr_date
End Property
Remove ":"
If Selection = EURO_USD.t_date Then
Debug.Print "Date already exist"
Else
Sheets("EURO_USD").Columns("A").End(xlDown).Offset(1, 0) = EURO_USD.t_date
End If
From Rory
Your t_Date property is returning a string - what is in the cell? A real date value? Is it formatted the same as the t_Date?
Using function datevalue solved the issue.

Enumeration in vb.net

while executing this below lines i got an error. Error:
Collection was modified; enumeration operation may not execute.
Help me to solve this.
Dim i As IEnumerator
Dim item As DataGridItem
Dim bChk As Boolean = False
i = dgOfferStatus.Items.GetEnumerator
For Each item In dgOfferStatus.Items
i.MoveNext()
item = i.Current
item = CType(i.Current, DataGridItem)
Dim chkItemChecked As New CheckBox
chkItemChecked = CType(item.FindControl("chkItemChecked"), CheckBox)
If chkItemChecked.Checked = True Then
Try
bChk = True
lo_ClsInterviewProcess.JobAppID = item.Cells(1).Text
lo_ClsInterviewProcess.candId = item.Cells(9).Text
Dim str, strSchedule1, strSchedule As String
Dim dspath As DataSet
Dim candidateId As Integer
''Moving the resume to Completed folder
ObjInterviewAssessment = New ClsInterviewAssessment
dspath = ObjInterviewAssessment.GetOffComPath(CInt(lo_ClsInterviewProcess.JobAppID), "GetHoldPath")
If dspath.Tables(0).Rows.Count > 0 Then
If Not IsDBNull(dspath.Tables(0).Rows(0).Item(0)) Then
str = dspath.Tables(0).Rows(0).Item(0)
strSchedule1 = str.Replace("Hold", "Completed")
End If
End If
Dim str1 As String
str1 = Server.MapPath(str).Trim
strSchedule = Server.MapPath(strSchedule1).Trim
Dim file1 As File
If file1.Exists(str1) Then
If file1.Exists(strSchedule) Then
file1.Delete(strSchedule)
End If
file1.Move(str1, strSchedule)
End If
''
intResult = lo_ClsInterviewProcess.UpdateApproveStatus(Session("EmployeeId"), strSchedule1)
BindHoldGrid()
If intResult > 0 Then
Alert.UserMsgBox("btnsearch", "Status Updated")
Else
Alert.UserMsgBox("btnsearch", "Status not Updated")
End If
Catch ex As Exception
ExceptionManager.Publish(ex)
Throw (ex)
End Try
End If
Next
If bChk = False Then
Alert.UserMsgBox("btnsearch", "Please Select any Candidate")
End If
'Catch ex As Exception
' ExceptionManager.Publish(ex)
'End Try
End Sub
Look at this part of your code. I think it's what causes your exception.
Dim i As IEnumerator
...
Dim item As DataGridItem
...
i = dgOfferStatus.Items.GetEnumerator
For Each item In dgOfferStatus.Items
i.MoveNext()
item = i.Current ' <-- here be dragons!? '
...
Next
What you're doing seems a little strange. You iterate through the same collection (dgOfferStatus.Items) twice, once with the For Each loop, and once manually using the i iterator. Then you modify items in your collection with item = i.Current. I believe it's this assignment that causes the exception.
(I also don't understand why you would do this. This assignment seems to be completeley superfluous, since i.Current and item should be identical since both iterators are at the same position in the collection.)
The exception basically tries to tell you that you may not modify a collection while you are iterating through it. But you seem to be doing exactly that.