[英]EXCEL VBA, Manual Outlook email sender, Class module Issue
I am still working on the problem that I have described in my 1st question on this topic. 我仍在处理我在有关该主题的第一个问题中描述的问题 。 For short refresh, it is an excel file which contains the list of email templates and attachments, to each list unit I have add the button which opens the template of the giving unit make there some changes, then attaches files and display the mail to the User. 为了简短刷新,它是一个excel文件,其中包含电子邮件模板和附件的列表,向每个列表单元添加了按钮,该按钮打开给定单元的模板,进行一些更改,然后附加文件并将邮件显示到用户。 User can amend mail if necessary and then send or not to send mail. 用户可以根据需要修改邮件,然后发送或不发送邮件。 I have tried several approaches described below. 我尝试了以下几种方法。 Unfortunately, I am stalled now on the issue with class module, that shortly described here . 不幸的是,我现在停滞在类模块的问题上, 这里简短介绍一下 。 I do have created a class module, such as 'EmailWatcher' and even make a small combination with method described here : 我确实已经创建了一个类模块,例如“ EmailWatcher”,甚至与此处描述的方法进行了较小的组合:
Option Explicit
Public WithEvents TheMail As Outlook.MailItem
Private Sub Class_Terminate()
Debug.Print "Terminate " & Now()
End Sub
Public Sub INIT(x As Outlook.MailItem)
Set TheMail = x
End Sub
Private Sub x_Send(Cancel As Boolean)
Debug.Print "Send " & Now()
ThisWorkbook.Worksheets(1).Range("J5") = Now()
'enter code here
End Sub
Private Sub Class_Initialize()
Debug.Print "Initialize " & Now()
End Sub
The change to following form does not make any change: 更改为以下形式不会进行任何更改:
Option Explicit
Public WithEvents TheMail As Outlook.MailItem
Private Sub Class_Terminate()
Debug.Print "Terminate " & Now()
End Sub
Public Sub INIT(x As Outlook.MailItem)
Set TheMail = x
End Sub
Private Sub TheMail_Send(Cancel As Boolean)
Debug.Print "Send " & Now()
ThisWorkbook.Worksheets(1).Range("J5") = Now()
'enter code here
End Sub
Private Sub Class_Initialize()
Debug.Print "Initialize " & Now()
End Sub
The module code is as follow: 模块代码如下:
Public Sub SendTo()
Dim r, c As Integer
Dim b As Object
Set b = ActiveSheet.Buttons(Application.Caller)
With b.TopLeftCell
r = .Row
c = .Column
End With
Dim filename As String, subject1 As String, path1, path2, wb As String
Dim wbk As Workbook
filename = ThisWorkbook.Worksheets(1).Cells(r, c + 5)
path1 = Application.ThisWorkbook.Path &
ThisWorkbook.Worksheets(1).Range("F4")
path2 = Application.ThisWorkbook.Path &
ThisWorkbook.Worksheets(1).Range("F6")
wb = ThisWorkbook.Worksheets(1).Cells(r, c + 8)
Dim outapp As Outlook.Application
Dim oMail As Outlook.MailItem
Set outapp = New Outlook.Application
Set oMail = outapp.CreateItemFromTemplate(path1 & filename)
subject1 = oMail.subject
subject1 = Left(subject1, Len(subject1) - 10) &
Format(ThisWorkbook.Worksheets(1).Range("D7"), "DD/MM/YYYY")
oMail.Display
Dim CurrWatcher As EmailWatcher
Set CurrWatcher = New EmailWatcher
CurrWatcher.INIT oMail
Set CurrWatcher.TheMail = oMail
Set wbk = Workbooks.Open(filename:=path2 & wb)
wbk.Worksheets(1).Range("I4") =
ThisWorkbook.Worksheets(1).Range("D7").Value
wbk.Close True
ThisWorkbook.Worksheets(1).Cells(r, c + 4) = subject1
With oMail
.subject = subject1
.Attachments.Add (path2 & wb)
End With
With ThisWorkbook.Worksheets(1).Cells(r, c - 2)
.Value = Now
.Font.Color = vbWhite
End With
With ThisWorkbook.Worksheets(1).Cells(r, c - 1)
.Value = "Was opened"
.Select
End With
End Sub
Finally I have made a class which is working and I have put some controls to check it as you can see from class module code. 最后,我制作了一个可以正常工作的类,并从类模块代码中看到了一些控件来对其进行检查。 But the problem is, it does not catch the Send event. 但是问题是,它无法捕获Send事件。 The class is terminating at the end of the sub. 该类在子句的结尾处终止。 Leaving the email fully to User. 将电子邮件完全留给用户。 The question is: where is mistake? 问题是:哪里出错了? Or how to leave the class module in so called "waiting mode", or maybe any other suggestions? 或者如何使类模块处于所谓的“等待模式”,或者还有其他建议? I so also consider the way to search for mails in the 'outbox' but the approach with Send event is much more in favour. 我也考虑在“发件箱”中搜索邮件的方法,但是发送事件的方法更受青睐。
Dim CurrWatcher As EmailWatcher
该行必须是全局的,在任何子例程之外。
I answered a similar question here and looking over that, I think that while you're on the right track, you've got a few things wrong with your implementation. 我在这里回答了类似的问题,并仔细研究了一下,我认为当您步入正轨时,您的实现存在一些错误。 Try this instead: 尝试以下方法:
Do the Class module as so, get rid of the unnecessary INIT
procedure and use the Class_Initialize
procedure to create the Mailitem
. 执行类模块,因此,摆脱不必要的INIT
程序和使用Class_Initialize
程序创建Mailitem
。
Option Explicit
Public WithEvents TheMail As Outlook.MailItem
Private Sub Class_Terminate()
Debug.Print "Terminate " & Now()
End Sub
Private Sub TheMail_Send(Cancel As Boolean)
Debug.Print "Send " & Now()
ThisWorkbook.Worksheets(1).Range("J5") = Now()
'enter code here
End Sub
Private Sub Class_Initialize()
Debug.Print "Initialize " & Now()
'Have Outlook create a new mailitem and get a handle on this class events
Set TheMail = olApp.CreateItem(0)
End Sub
Example for use in normal module, tested & confirmed this is working and will handle multiple emails (which my previous answer didn't accomplish). 在正常模块中使用的示例,经过测试并确认这可以正常工作,并且可以处理多封电子邮件(我以前的回答没有完成)。
Option Explicit
Public olApp As Outlook.Application
Public WatchEmails As New Collection
Sub SendEmail()
If olApp Is Nothing Then Set olApp = CreateObject("Outlook.Application")
Dim thisMail As New EmailWatcher
WatchEmails.Add thisMail
thisMail.TheMail.Display
thisMail.TheMail.To = "someone@email.com"
thisMail.TheMail.Subject = "test"
thisMail.TheMail.Display
End Sub
How's it work? 如何运作? First, we make sure we have an Outlook.Application
instance to work with. 首先,我们确保要使用一个Outlook.Application
实例。 This will be scoped as a Public
in module so it will be available to other procedures & classes. 这将以“ Public
”模块为范围,因此可用于其他过程和类。
Then, we create a new instance of our EmailWatcher
class, which raises the Class_Initialize
event. 然后,我们创建的新实例EmailWatcher
类,这提高了Class_Initialize
事件。 We leverage this event, and the already handled instance of Outlook.Application
to create & assign the TheMail
object event handler. 我们利用此事件和已处理的Outlook.Application
实例来创建和分配TheMail
对象事件处理程序。
We store these in a Public
collection so that they remain in scope even after the SendMail
procedure runtime is over. 我们将它们存储在Public
集合中,以便即使在SendMail
过程运行时结束后,它们也仍然在作用域中。 This way you can create several emails and they will all have their events monitored. 这样,您可以创建多封电子邮件,并且将全部监视其事件。
From that point on, thisMail.TheMail
represents the MailItem
whose events are being monitored under Excel, and invoking the .Send
method on this object (via VBA) or manually sending the email should raise the TheMail_Send
event procedure. 从那时起, thisMail.TheMail
代表MailItem
其事件正在Excel中监视,并且对此对象(通过VBA)调用.Send
方法或手动发送电子邮件应引发TheMail_Send
事件过程。
Thanks a lot for help and support, I have finally done it. 非常感谢您的帮助和支持,我终于做到了。
As I do use templates of the mails it takes some time to figure out how to add them to collection. 当我使用邮件模板时,需要花费一些时间来弄清楚如何将其添加到邮件中。
Here is my solution. 这是我的解决方案。 Class module: 类模块:
Option Explicit
Public WithEvents themail As Outlook.MailItem
Private Sub Class_Terminate()
Debug.Print "Terminate " & Now()
End Sub
Private Sub themail_Send(Cancel As Boolean)
Debug.Print "Send " & Now()
Call overwrite(r, c)
'enter code here
End Sub
Private Sub Class_Initialize()
Debug.Print "Initialize " & Now()
'Have Outlook create a new mailitem and get a handle on this class events
Set themail = OutApp.CreateItem(0)
Set themail = oMail
End Sub
Module: 模块:
Public Sub SendTo1()
Dim r, c As Integer
Dim b As Object
Set b = ActiveSheet.Buttons(Application.Caller)
With b.TopLeftCell
r = .Row
c = .Column
End With
Dim filename As String, subject1 As String, path1, path2, wb As String
Dim wbk As Workbook
filename = ThisWorkbook.Worksheets(1).Cells(r, c + 5)
path1 = Application.ThisWorkbook.Path &
ThisWorkbook.Worksheets(1).Range("F4")
path2 = Application.ThisWorkbook.Path &
ThisWorkbook.Worksheets(1).Range("F6")
wb = ThisWorkbook.Worksheets(1).Cells(r, c + 8)
Dim OutApp As Outlook.Application
Dim oMail As Outlook.MailItem
Set OutApp = New Outlook.Application
Set oMail = OutApp.CreateItemFromTemplate(path1 & filename)
oMail.Display
subject1 = oMail.subject
subject1 = Left(subject1, Len(subject1) - 10) &
Format(ThisWorkbook.Worksheets(1).Range("D7"), "DD/MM/YYYY")
Dim currwatcher As EmailWatcher
Set currwatcher = New EmailWatcher
currwatcher.INIT oMail
Set currwatcher.themail = oMail
Set wbk = Workbooks.Open(filename:=path2 & wb)
wbk.Worksheets(1).Range("I4") = ThisWorkbook.Worksheets(1).Range("D7").Value
wbk.Close True
ThisWorkbook.Worksheets(1).Cells(r, c + 4) = subject1
With oMail
.subject = subject1
.Attachments.Add (path2 & wb)
End With
With ThisWorkbook.Worksheets(1).Cells(r, c - 2)
.Value = Now
.Font.Color = vbWhite
End With
With ThisWorkbook.Worksheets(1).Cells(r, c - 1)
.Value = "Was opened"
.Select
End With
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.