Excel - Match placeholder with valid value in VBA - vba

I want to make an editable email template where everyone can update the email and assign to which user they want to sent which email. The email templates are from another sheet. Every template has its own email ID.
I want to match the template with the table that contain all of the information needed. So, whenever user input the email ID, it will mapped the value with thee placeholder in the email template.
So far, here is what I have been working on with the email template. But right now it just grab all of the value from the cell. Which is breakable whenever I add columns or rows.
Sub Mail_with_outlook2()
Dim mainWB As Workbook
Dim otlApp As Object
Dim olMail As Object
Dim olMailItem As Object
Dim Doc As Object
Dim SendID
Dim CCID
Dim Subject
Dim Body
Dim WrdRng As Object
Dim result
Dim i As Long
Set otlApp = CreateObject("Outlook.Application")
Set olMail = otlApp.CreateItem(0)
Set mainWB = ActiveWorkbook
SendID = mainWB.Sheets("Email Template").Range("C3").Value
CCID = mainWB.Sheets("Email Template").Range("D3").Value
Subject = mainWB.Sheets("Email Template").Range("E3").Value
Body = mainWB.Sheets("Email Template").Range("F3").Value
Dim splitBody
splitBody = Split(Body, "<%")
For i = 0 To UBound(splitBody)
result = Replace(Body, ">", "K")
Next i
With olMail
.to = SendID
If CCID <> "" Then
.CC = CCID
End If
.Subject = Subject
.Display
End With
Set Doc = olMail.GetInspector.WordEditor
Set WrdRng = Doc.Range(Start:=0, End:=0)
WrdRng.Select
mainWB.Sheets("Email Template").Range("F3").Copy
WrdRng.Paste
MsgBox ("you Mail has been sent to " & SendID)
End Sub

Table + Match function
Consider turning your template sheet data into Excel Table. Then you can use the "table object" aka. ListObject to refer to it's columns by their name (column headings).
To find the relative position of the ID inside the table, you can use WorksheetFunction.Match.
Code with examples
In my code, the sheet where the parameters for the mail template are is called "IssueTemplates".
The table is called "IssueTemplatesTable".
Sub GetDataFromTable()
Dim IssueTemplatesTable As ListObject
Dim ID_Searched As Integer 'Input variable
Dim ID_RelativeRow As Integer 'Input relative row inside the table
Dim Var1 As String 'Output variable
Set IssueTemplatesTable = ThisWorkbook.Sheets("IssueTemplates").ListObjects("IssueTemplatesTable")
'''''''''''''''''EXAMPLE 1'''''''''''''''''''''''''
ID_Searched = 17 'Input: "No" of template
With IssueTemplatesTable
ID_RelativeRow = WorksheetFunction.Match(ID_Searched, .ListColumns("No").DataBodyRange, 0)
Var1 = .DataBodyRange(ID_RelativeRow, .ListColumns("Issue Type").Index)
End With 'IssueTemplatesTable
MsgBox Var1 'Output: "Others"
'''''''''''''''''EXAMPLE 2'''''''''''''''''''''''''
ID_Searched = 25 'Input: "No" of template
With IssueTemplatesTable
ID_RelativeRow = WorksheetFunction.Match(ID_Searched, .ListColumns("No").DataBodyRange, 0)
Var1 = .DataBodyRange(ID_RelativeRow, .ListColumns("Issue Type").Index)
End With 'IssueTemplatesTable
MsgBox Var1 'Output: "Mapping"
End Sub

Related

VBA send email with specific column

i have a excel list and and i want to make a button to send an email in the list using template, the target email address is in column K, but i only want to send it if column A is showing YES.
I wrote a script to loop every row i want and see if column A has "YES" or not, if yes then refer to another macro.
but i got stuck in anther macro, i cant specify .to = column K
Here is the loop script to find if column A has YES:
sub agreement2 ()
dim startrow as integer
startrow = 9
dim mylastrow3 as integer
lastrow3 = activesheet.cells(rows.count, 1).end(xlup).row
dim i as integer
for i = 9 to lastrow3
if (cells(i, 1).value = "YES") then
send_letter
end if
end sub
Here is my send_letter script
Sub send_letter()
Dim Subject
Dim Body
Dim otlapp As Object
Dim olMail2 As Object
Dim ws As Object
Set otlapp = CreateObject("Outlook.Application")
Set olMail2 = otlapp.CreateItemFromTemplate("\\cpadm001.corp.ocalwa.com\clk\DEPT\CLKDEPT6\IMT\SAO\SSC\Team\Team1\New Joiner Script\agreement.oft")
Set doc2 = olMail2.GetInspector.WordEditor
Set ws = ThisWorkbook.Worksheets("Send Letters")
vTemplateBody2 = olMail2.HTMLBody
Subject2 = "Agreement Letter"
HTMLBody2 = vTemplateBody2
With olMail2
.To = ????????????????.Value
.Subject = Subject2
Set WrdRng = doc2.Range
WrdRng.Paste
.Send
End With
End Sub
Could anyone help with the column K thing. thank you so much.
Change send_letter to send_letter(r)
Alter call from send_letter to send_letter i
Your final code will be: .To = Cells(r, "K").Value

Split Word document into multiple parts and keep the text format

My Task
Split a Word document into multiple parts based on a delimiter while preserving the text format.
Where I am?
I tried a basic example with one document but without an array and it worked.
Option Explicit
Public Sub CopyWithFormat()
Dim docDestination As Word.Document
Dim docSource As Word.Document
Set docDestination = ActiveDocument
Set docSource = Documents.Add
docSource.Range.FormattedText = docDestination.Range.FormattedText
docSource.SaveAs "C:\Temp\" & "test.docx"
docSource.Close True
End Sub
Where do I stuck?
I put the whole document into an array and loop through it. Right not I get an error 424 - Object necessary on this line:
docDestination.Range.FormattedText = arrNotes(I).
I also tried these four variants without luck:
docDestination.Range.FormattedText = arrNotes(I).Range.FormattedText
docDestination.Range.FormattedText = arrNotes(I).FormattedText
docDestination.Range.FormattedText = arrNotes.Range.FormattedText(I)
docDestination.Range.FormattedText = arrNotes.FormattedText(I)
Could you please help and point me into the right direction on how to access the array properly?
My Code
Option Explicit
Sub SplitDocument(delim As String, strFilename As String)
Dim docSource As Word.Document
Dim docDestination As Word.Document
Dim I As Long
Dim X As Long
Dim Response As Integer
Dim arrNotes
Set docSource = ActiveDocument
arrNotes = Split(docSource.Range, delim)
For I = LBound(arrNotes) To UBound(arrNotes)
If Trim(arrNotes(I)) <> "" Then
X = X + 1
Set docDestination = Documents.Add
docDestination.Range.FormattedText = arrNotes(I) 'throws error 424
docDestination.SaveAs ThisDocument.Path & "\" & strFilename & Format(X, "0000")
docDestination.Close True
End If
Next I
End Sub
Sub test()
'delimiter & filename
SplitDocument "###", "Articles "
End Sub
Range.FormattedText returns a range object. The Split function, on the other hand, returns an array of strings which don't include formatting. Therefore your code should find the portion of the document you wish to copy and assign that part's FormattedText to a variable declared as Range. That variable could then be inserted into another document.
Private Sub CopyRange()
Dim Src As Range, Dest As Range
Dim Arr As Range
Set Src = Selection.Range
Set Arr = Src.FormattedText
Set Dest = ActiveDocument.Range(1, 1)
Dest.FormattedText = Arr
End Sub
The above code actually works. All you would need to do is to find a way to replace the Split function in your concept with a method that identifies ranges in the source document instead of strings.

Excel/VBA iterate over cells in a column get eMail from cell, validate and send automatic Notification

I want to create an Excel file where people can enter their E-Mail address and as soon as 5 People added their E-Mail an Message is sent to all those E-Mails.
To execute the VBA-Makro when saving i do the following:
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
'My Code is here
End Sub
I try to loop over one column but didn't found a good solution for this - currently I have set a Rage from B2 to B99
I need to get the E-Mail from the cell, ignore empty/null cells and I need to somehow check the E-Mail if its valid (RegEx?)
Dim eMailList As String
Dim eMailCount As Integer
eMailCount = 0
eMailList = ""
Dim eMail As String
Dim rng As Range: Set rng = ThisWorkbook.Worksheets("Tabelle1").Range("B2:B99")
Dim i As Integer
For i = 1 To rng.Rows.Count
eMail = rng.Cells(RowIndex:=i, ColumnIndex:="B").Text
eMailList = eMailList & eMail & "; "
Next
Set objOutlook = CreateObject("Outlook.Application")
Set objMail = objOutlook.CreateItem(0)
With objMail
.To = eMailList
.Subject = "DummyText"
.Body = "DummyText"
.send
End With
My Questions are:
How can I easy iterate over the cells in one specific Column?
How can I get the eMail from the cell - .Text .Value?
How to use Regular Expressions in VBA/Excel to validate Email?
How can I list the EMails and send a message to each E-Mail
Im glad for any help/tip/recommendation
Thanks in Advance
The code below will get you started, explanations inside the codes comments:
Dim Rng As Range, C As Range
Set Rng = ThisWorkbook.Worksheets("Tabelle1").Range("B2:B99")
' loop through all cells in Range (Column "B")
For Each C In Rng
If Trim(C.Value2) <> "" Then ' <-- check that cell isn't empty
' --- Add Here another IF criteria to validate your E-Mail ---
eMail = Rng.Value2 ' <-- read the value2 of the cell (without the cell's format)
eMailList = eMailList & eMail & "; "
End If
Next C

Need correct macro coding to attach documents a/o files to Outlook from Excel Spreadsheet

I have a macro that searches a contact list that pulls data from a list of contacts in Excel, and prepares an email to be sent in Outlook.
Most of this macro works successfully. I am almost finished.
I also need it to search a folder (using the filename to be entered in cell A8) and attach the appropriate file to the emails.
(Folder path: C:\Users\SERGIL\Desktop\VATS )
Below is the code I have thus far:
Public Sub SendEmails()
Const cSUBJECT As String = "C2"
Const cBODY As String = "C3"
Const cSTART_ROW_INDEX As String = "C4"
Const cEND_ROW_INDEX As String = "C5"
Const cMAIL_TO_COLUMN As String = "G" ' The column with the email addresses in it
Const cCOMPANY_NAME_COLUMN As String = "B" ' The column with the Vendor/Company Names in it
'Put as many email addresses here as you want, just seperate them with a semicolon
Const cCC_EMAIL_ADDRESSES As String = "C6"
Const cFROM_ADDRESS As String = "C7"
Dim iRowCount As Integer
Dim iEndRow As Integer
'Grab the current open worksheet object
Dim oSheet As Worksheet
Set oSheet = ActiveSheet
iRowCount = oSheet.Range(cSTART_ROW_INDEX).Value2 ' Get the Start Value
iEndRow = oSheet.Range(cEND_ROW_INDEX).Value2 ' Get the End Value
Dim dBatchStart As Date
Dim dBatchEnd As Date
Dim sVendorName As String
Dim sEmail As String
Dim sSubject As String
Dim sBody As String
'Outlook must already be open, attach to the open instance
Dim oOutlook As Outlook.Application
Set oOutlook = GetObject(, "Outlook.Application")
'Declare a new draft email object
Dim oMail As Outlook.MailItem
'Start iterating through all the rows of mail, creating a new draft each loop
Do Until iRowCount = (iEndRow + 1)
'Actually instantiate the new draft email object
Set oMail = oOutlook.CreateItem(olMailItem)
'Display the draft on screen to the user can see and validate it
oMail.Display
'Set the TO address based on the data in the sheet
oMail.To = oSheet.Range(cMAIL_TO_COLUMN & iRowCount).Value2
'Get the subject, also, substitute the tags for Company and Start Date with the values in the sheet
sSubject = oSheet.Range(cSUBJECT).Value2
sSubject = Replace(sSubject, "<DATE FOR THAT VENDOR GROUP>", Format(dBatchStart, "Long Date"))
sSubject = Replace(sSubject, "<COMPANY>", oSheet.Range(cCOMPANY_NAME_COLUMN & iRowCount).Value2)
'Now insert the formatted subject into the draft email
oMail.Subject = sSubject
'Get the Body, substitute the tags for Start Date and End Date with the values in the sheet
sBody = oSheet.Range(cBODY).Value2
'Now insert the formatted Body into the draft email
oMail.HTMLBody = sBody
'Now add attachments
oMail.HTMLBody = sBody
'Set the CC address based on the Constant at the top
oMail.CC = oSheet.Range(cCC_EMAIL_ADDRESSES).Value2
oMail.Save
'Set the actual sender of the name. It won't display for the user, but will actually sent as that address
oMail.SentOnBehalfOfName = oSheet.Range(cFROM_ADDRESS).Value2
oMail.Save
'The draft mail item is now complete.
'The from address will need to be changed manually.
'The user will need to actually send the email once reviewed.
iRowCount = iRowCount + 1
Loop
With objMail
.Attachments.Add rngAttach.Value
.Display 'Instead of .Display, you can use .Send to send the email _
or .Save to save a copy in the drafts folder
End With
End Sub
-- I am receiving an error with this segment of the code:
With objMail
.Attachments.Add rngAttach.Value
.Display 'Instead of .Display, you can use .Send to send the email _
or .Save to save a copy in the drafts folder
The Add method of the Attachments class accepts four parameters. The Source parameter (the first one) should be a file (represented by the full file system path with a file name) or an Outlook item that constitutes the attachment.
It seems you need to replace the rngAttach.Value statement with a valid parameter (a file or Outlook object).

Copy Excel chart to Outlook mail message

I have email addresses in column A, and a chart object in the same sheet.
For each email address, I want to create a new mail in Outlook and paste the Excel chart into the email body.
The problem with my attempt (below) is that the chart does not get pasted into the mail body. How do I fix this?
This my code:
Sub smail()
Dim r As Integer
Dim o As Outlook.Application
Dim m As Outlook.MailItem
Set o = New Outlook.Application
r = 1
Do While Cells(r, 1) <> ""
Set m = o.CreateItem(olMailItem)
m.To = Cells(r, 1)
m.CC = "xyz#anc.com"
m.BCC = "abc#xyz.com"
m.Subject = "Test"
ActiveChart.ChartArea.Copy
Set wEditor = o.ActiveInspector.WordEditor
'm.Body = Paste
wEditor.Application.Selection.Paste
m.Send
r = r + 1
Set m = Nothing
Loop
End Sub
I think the problem with this line
wEditor.Application.Selection.Paste
is that nothing is selected, i.e. .Selection returns Nothing, as long as the message is not visible. To solve this, make it visible before pasting:
m.Display
That worked for me.
Also, you should always declare all your variables using Dim, including wEditor:
Dim wEditor As Word.Document