#excel #vba
#превосходить #vba
Вопрос:
В настоящее время я пытаюсь понять, как создать рабочую книгу, которая может выполнять следующие действия:
- Отправьте электронное письмо каждому пользователю в списке (MailInfo — лист1 — состоит из двух столбцов. A = Пользователи, B = Адреса электронной почты
- Прикрепите строки из четырех листов со строками, относящимися только к ним (столбцы A:H) (Пользователи для электронной почты указаны в столбце A листа 1, а они перечислены в столбце H на остальных 4 листах. В настоящее время всего 4 листа, которые имеют диапазоны)
Я пытаюсь добиться того, чтобы код проходил по списку агентов на листе 1, а затем добавлял таблицы в текст письма только с теми строками, которые имеют к ним отношение.
Моя проблема в том, что я проверил документацию Рона де Брюна, и я могу создавать электронные письма с полными диапазонами/таблицами, но я не думаю, что они работают для того, что я имею в виду. Когда я собираю кусочки воедино, мне кажется, что я все усложняю. Я привел приведенный ниже код в качестве ссылки. На данный момент он просто откроет электронное письмо для каждого пользователя со всеми полными таблицами.
Если бы кто-нибудь мог дать мне несколько советов или помочь мне, это очень помогло бы мне.
Текущий код, до которого я смог добраться, следующий (из документации Рона де Брюна), который позволяет мне открывать электронные письма для каждой строки в списке рассылки 1 (я переименовал его в MailInfo), и мне пришлось добавить столбец B, чтобы добавить адреса электронной почты. Однако мне нужно выяснить код, позволяющий фильтровать значения в диапазонах для каждого пользователя в столбце A в MailInfo.
Sub Send_Row_Or_Rows_1() 'For Tips see: http://www.rondebruin.nl/win/winmail/Outlook/tips.htm 'Don't forget to copy the function RangetoHTML in the module. 'Working in Excel 2000-2016 Dim OutApp As Object Dim OutMail As Object Dim rng As Range Dim rng1 As Range Dim Ash As Worksheet Dim Cws As Worksheet Dim Rcount As Long Dim Rnum As Long Dim FilterRange As Range Dim FieldNum As Integer Dim mailAddress As String On Error GoTo cleanup Set OutApp = CreateObject("Outlook.Application") With Application .EnableEvents = False .ScreenUpdating = False End With 'Set filter sheet, you can also use Sheets("MySheet") Set Ash = ActiveSheet 'Set filter range and filter column (Column with names) Set FilterRange = Ash.Range("A1:H" amp; Ash.Rows.Count) FieldNum = 1 'Filter column = A because the filter range start in A 'Add a worksheet for the unique list and copy the unique list in A1 Set Cws = Worksheets.Add FilterRange.Columns(FieldNum).AdvancedFilter _ Action:=xlFilterCopy, _ CopyToRange:=Cws.Range("A1"), _ CriteriaRange:="", Unique:=True 'Count of the unique values the header cell Rcount = Application.WorksheetFunction.CountA(Cws.Columns(1)) 'If there are unique values start the loop If Rcount gt;= 2 Then For Rnum = 2 To Rcount 'Filter the FilterRange on the FieldNum column FilterRange.AutoFilter Field:=FieldNum, _ Criteria1:=Cws.Cells(Rnum, 1).Value 'Look for the mail address in the MailInfo worksheet mailAddress = "" On Error Resume Next mailAddress = Application.WorksheetFunction. _ VLookup(Cws.Cells(Rnum, 1).Value, _ Worksheets("Mailinfo").Range("A1:B" amp; _ Worksheets("Mailinfo").Rows.Count), 2, False) On Error GoTo 0 If mailAddress lt;gt; "" Then With Ash.AutoFilter.Range On Error Resume Next Set rng = Sheets("SampleTable1").Range("A1:H10").SpecialCells(xlCellTypeVisible) Set rng1 = Sheets("SampleTable2").Range("A1:H10").SpecialCells(xlCellTypeVisible) On Error GoTo 0 End With Set OutMail = OutApp.createitem(0) On Error Resume Next With OutMail .To = mailAddress .Subject = "Test mail" .HTMLBody = RangetoHTML(rng) amp; "lt;brgt;" amp; RangetoHTML(rng1) .display 'Or use Send End With On Error GoTo 0 Set OutMail = Nothing End If 'Close AutoFilter Ash.AutoFilterMode = False Next Rnum End If cleanup: Set OutApp = Nothing Application.DisplayAlerts = False Cws.Delete Application.DisplayAlerts = True With Application .EnableEvents = True .ScreenUpdating = True End With End Sub Function RangetoHTML(rng As Range) ' Changed by Ron de Bruin 28-Oct-2006 ' Working in Office 2000-2016 Dim fso As Object Dim ts As Object Dim TempFile As String Dim TempWB As Workbook TempFile = Environ$("temp") amp; "/" amp; Format(Now, "dd-mm-yy h-mm-ss") amp; ".htm" 'Copy the range and create a new workbook to past the data in rng.Copy Set TempWB = Workbooks.Add(1) With TempWB.Sheets(1) .Cells(1).PasteSpecial Paste:=8 .Cells(1).PasteSpecial xlPasteValues, , False, False .Cells(1).PasteSpecial xlPasteFormats, , False, False .Cells(1).Select Application.CutCopyMode = False On Error Resume Next .DrawingObjects.Visible = True .DrawingObjects.Delete On Error GoTo 0 End With 'Publish the sheet to a htm file With TempWB.PublishObjects.Add( _ SourceType:=xlSourceRange, _ filename:=TempFile, _ Sheet:=TempWB.Sheets(1).Name, _ Source:=TempWB.Sheets(1).UsedRange.Address, _ HtmlType:=xlHtmlStatic) .Publish (True) End With 'Read all data from the htm file into RangetoHTML Set fso = CreateObject("Scripting.FileSystemObject") Set ts = fso.GetFile(TempFile).OpenAsTextStream(1, -2) RangetoHTML = ts.ReadAll ts.Close RangetoHTML = Replace(RangetoHTML, "align=center x:publishsource=", _ "align=left x:publishsource=") 'Close TempWB TempWB.Close savechanges:=False 'Delete the htm file we used in this function Kill TempFile Set ts = Nothing Set fso = Nothing Set TempWB = Nothing End Function
Ответ №1:
Для каждого пользователя объедините отфильтрованные данные с 4 листов на 1 временный лист, а затем используйте RangeToHtml
.
Option Explicit Sub Send_Row_Or_Rows_1() Dim wb As Workbook Dim wsInfo As Worksheet, ws As Worksheet, wsTmp As Worksheet Dim i As Long, lastrow As Long Set wb = ThisWorkbook ' sheets to copy Dim data(3) As Worksheet Set data(0) = wb.Sheets("SampleTable1") Set data(1) = wb.Sheets("SampleTable2") Set data(2) = wb.Sheets("SampleTable3") Set data(3) = wb.Sheets("SampleTable4") ' add a temporary sheet Application.DisplayAlerts = False For Each ws In Sheets If ws.name = "~tmp" Then ws.Delete Next Set wsTmp = Sheets.Add wsTmp.name = "~tmp" Application.DisplayAlerts = True Dim rngCopy As Range Dim sName As String, sAddr As String Dim n As Long, k As Long, r As Long ' outlook Dim appOut As Object, OutMail As Object Set appOut = CreateObject("Outlook.Application") ' scan users Set wsInfo = wb.Sheets("Mail Info") With wsInfo lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row ' for each user For i = 2 To lastrow sName = Trim(.Cells(i, "A")) sAddr = Trim(.Cells(i, "B")) r = 1 wsTmp.Cells.Clear ' consolidate each sheet on tmp sheet For k = 0 To UBound(data) Set ws = data(k) ' filter on name in col H 8 With ws.UsedRange .AutoFilter .AutoFilter 8, sName ' col H Set rngCopy = .SpecialCells(xlCellTypeVisible) rngCopy.Copy wsTmp.Cells(r, 1) If r gt; 1 Then wsTmp.Rows(r).Delete ' leave 1 header r = wsTmp.Cells(ws.Rows.Count, "A").End(xlUp).Row 2 ' leave blank line .AutoFilter End With Next ' email sheet If r gt; 1 Then Set OutMail = appOut.createitem(0) With OutMail .To = sAddr .Subject = "Test Mail to " amp; sName .HTMLBody = RangetoHTML(wsTmp.UsedRange) .display 'Or use Send End With Set OutMail = Nothing n = n 1 End If Next End With Application.DisplayAlerts = False 'ws.Sheets("~tmp").Delete Application.DisplayAlerts = True MsgBox n amp; " emails sent", vbInformation End Sub
Комментарии:
1. Это делает это! В итоге я закомментировал строку, которая удаляет дополнительные заголовки, и добавил столбец в свои таблицы. Остальное, что я сделал, это просто отформатировал фактические таблицы в другом подразделе, предназначенном для очистки. Но это делает именно то, что мне нужно, и это достаточно понятно для меня, чтобы использовать его для расширения. Большое спасибо за потраченное время!!
2. Последний вопрос, который у меня может возникнуть (и это только в том случае, если у вас есть время для этого), заключается в том, можно ли добавить дополнительный заголовок в каждую таблицу.. Так, например, в дополнение к отображению всех 4 таблиц и добавлению значений заголовков для каждой из них, могу ли я добавить дополнительный заголовок, сохранив, таким образом, первые 2 строки всех 4 таблиц? в принципе, может ли он сохранить первые 2 независимо от содержимого, а затем отфильтровать данные?
3. @Black Вы добавляете фильтры в заголовки строки 2, но хотите также включить строку 1 в электронное письмо ?
4. Я мог бы в конце добавить строку в верхней части каждой из 4 таблиц, это в основном описание этой таблицы, поэтому, например: Таблица 1 предназначена для случаев, требующих внимания «Требует внимания», Таблица 2 «В ожидании 7 дней» и т. Д. Поэтому я подумываю о том, чтобы добавить это, в противном случае я могу просто добавить это в качестве комментария в качестве дополнительной колонки к каждому из них. Я пытаюсь найти способ удалить таблицы, в которых нет совпадений/результатов (например, иногда у пользователя может не быть данных в таблицах 3 и 4).
5.
rngCopy
может быть несмежным, поэтому способ проверить, есть ли строки под заголовкомIf rngCopy.Rows.Count gt; 1 or rngCopy.Areas.Count gt; 1 Then