简体   繁体   English

EXCEL VBA,Outlook手动电子邮件发件人,类模块问题

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM