Link to home
Start Free TrialLog in
Avatar of schmir1
schmir1Flag for United States of America

asked on

vbSendEmail poSendMail_SendFailed usage

I'm trying to get poSendMail_SendFailed but I don't understand the class structure.  Below is the code that I put into poSendMail_SendFailed.  I get this error:
   vbsendmail 503.5.5.0 sender already specified

I'm thinking that I can't call vbSendEmail  from inside the error handler.  I could set a global flag but there must be a better way.  Any ideas?
Private Sub poSendMail_SendFailed(Explanation As String)
' vbSendMail 'SendFailed Event
  Dim strSubject As String
  Dim strMessage As String
  
'  MsgBox ("Your attempt to send mail failed for the following reason(s): " & vbCrLf & Explanation)
  strSubject = "DTL Database E-Mail could not be sent"
  strMessage = "Your attempt to send mail failed for the following reason(s): " & vbCrLf & Explanation
  Call Send_EMail_to_Man("Maintenance_Email", strSubject, strMessage & vbNewLine & "(EM-41)")
End Sub

Open in new window

Avatar of Scott McDaniel (EE MVE )
Scott McDaniel (EE MVE )
Flag of United States of America image

Assuming this is the same situation you were working with earlier, where you've sunk the Events from the poSendMail class into your vbSendMail class:

You really should NOT retry this, at least in my opinion. What should happen in this case is the top level class (the vbSendMail class) should do nothing more than report back to the UI and clean up (destroy objects, close connections, log errors, etc etc), and then your UI logic should take over from there.

What I would do is build a WithEvents setup for vbSendEmail, and then Raise a relevant event back to the UI. To do that, at the top of your vbSendMail class, add a new Event:

Event SendMailFailed()

In that vbSendMail class, add code like this to the SendFailed event:

Private Sub poSendMail_SendFailed(Explanation As String)
  RaiseEvent SendMailFailed()
End Sub

Back on the UI layer, make SURE to declare your vbSendMail class using the WithEvents keyword. If you're doing this from a form, then you'd declare that at the top of the form's Code module, in the General Declarations section of the Form:

[General Declarations]

Private WithEvents mclsSendMail As cSendMail

Once you've done this, the Properties and Methods of that object (mclsSendMail) are available to you. Locate the object in the leftside dropdown, then examine the rightside dropdown. You should see the SendMailFailed event listed there. Select it, and Access will build the VBA stubs to allow you to write code.

So when your cSendMail is informed of an Error in the poSendMail class (via the SendFailed event), you then just pass that along to the UI, where you can decide what to do with it.

You can also pass along the Explanation text to the UI if you wish. Just declare your Event like this:

Event SendMailFailed(FailCode As String)

And then modify the SendFailed code like this:

Private Sub poSendMail_SendFailed(Explanation As String)
  RaiseEvent SendMailFailed(Explanation)
End Sub

This will pass that text along to the UI layer, and you can do with it what you wish - restart the process, inform the user, etc etc.
Avatar of schmir1

ASKER

Thanks for all the detail.  I've got one problem.  My common e-mail code is in a common module, not a form module.  Access give me a "Only valid in object Module" compile error on the WithEvents for this line:
  Private WithEvents mclsSendMail As cSendMail

I suppose I could put it in with the Switchboard code or I could create another dummy form and move all my e-mail code there (not the class stuff).  What do you think?  Or is there any way to make a common module work with WithEvents?
Avatar of schmir1

ASKER

I'm getting the RaiseEvent to fire but not catching it in my Switchboard form module.  Note:  This module is not the same as what calls SMTP_EMail_Sender if that makes a difference.  As noted above, my e-mail code is in a common module except for poSendMail_SendFailed.
This code is in cSendMail Class Module.  It does break as indicated in the code comment
------------------------------------
Option Compare Database
Option Explicit
Private WithEvents poSendMail As vbSendMail.clsSendMail  'need to be a class module for WithEvents to work
Event SendMailFailed(FailCode As String)

Private Sub poSendMail_SendFailed(Explanation As String)
  RaiseEvent SendMailFailed(Explanation)  '*************breakpoint does happen here
End Sub
---------------------------------------


This code is in my Switchboard Module and it does NOT break as indicated in the code comment
------------------------------------------------
Option Compare Database
Option Explicit
Private WithEvents mclsSendMail As cSendMail

Private Sub mclsSendMail_SendMailFailed(FailCode As String)
'Note: vbSendMail 'SendFailed Event
  Dim strSubject As String
  Dim strMessage As String

'  MsgBox ("Your attempt to send mail failed for the following reason(s): " & vbCrLf & Explanation)
  strSubject = "DTL Database E-Mail could not be sent"   '**************Break does NOT occur here
  strMessage = "Your attempt to send mail failed for the following reason(s): " & vbCrLf & FailCode
  Call Send_EMail_to_Man("Maintenance_Email", strSubject, strMessage & vbNewLine & "(EM-41)")
End Sub
-----------------------------------------

Open in new window

You can't use WithEvents in a Standard Module, as the VBA Compiler has warned. If you want to use WithEvents, you'll have to move the vbSendMail code to a Class module, and then declare that new Class using WithEvents. This will "sink" the events into the host container, and allow you to process those events as they occur.

You would be far, far better off moving this to a proper Class module and working from there. You could kludge this sort of behavior by include a Function in your receiving form, and having your vbSendMail call that function, but this really negates the concept of modular programming. Not that I'm a slave to that, but if you're working with OOP principles you should strive to adhere to those principles.

Avatar of schmir1

ASKER

Let me see if I understand what you are saying.  You are saying to move the code from the vbSendMail.dll into a class module then use it.  How would I use it?  Below is my class module now (cSendMail):
Option Compare Database
Option Explicit
' *****************************************************************************
' Required declaration of the vbSendMail component (withevents is optional)
' You also need a reference to the vbSendMail component in the Project References
' *****************************************************************************
Private WithEvents poSendMail As vbSendMail.clsSendMail  'need to be a class module for WithEvents to work
Event SendMailFailed(FailCode As String)

Private Sub poSendMail_SendFailed(Explanation As String)
  RaiseEvent SendMailFailed(Explanation)  'breakpoint does happen here
End Sub

Public Sub SMTP_EMail_Sender(strRecipient As String, strSubject As String, strMessage As String, Optional strForm As String, Optional strCC As String)
'This routine sends e-mail using vbSendMail.dll
  Dim strServer As String
  Dim strFromDisplayName As String
  Dim strFrom As String
  
  Set poSendMail = New clsSendMail
  strServer = "mail.medtronic.com"
  strFrom = "robert.schmitt@medtronic.com"
  strFromDisplayName = "DTL Database"
  
  With poSendMail
    ' **************************************************************************
    ' Optional properties for sending email, but these should be set first
    ' if you are going to use them
    ' **************************************************************************
    .SMTPHostValidation = VALIDATE_NONE         ' Optional, default = VALIDATE_HOST_DNS
    .EmailAddressValidation = VALIDATE_SYNTAX   ' Optional, default = VALIDATE_SYNTAX
    .Delimiter = ";"                            ' Optional, default = ";" (semicolon)

    ' **************************************************************************
    ' Basic properties for sending email
    ' **************************************************************************
    .SMTPHost = strServer                  ' Required the fist time, optional thereafter
    .from = strFrom                       ' Required the fist time, optional thereafter
    .FromDisplayName = strFromDisplayName         ' Optional, saved after first use
    .Recipient = strRecipient                     ' Required, separate multiple entries with delimiter character
    .RecipientDisplayName = strRecipient      ' Optional, separate multiple entries with delimiter character
    .CcRecipient = strCC                        ' Optional, separate multiple entries with delimiter character
'    .CcDisplayName = txtCcName                  ' Optional, separate multiple entries with delimiter character
'    .BccRecipient = txtBcc                      ' Optional, separate multiple entries with delimiter character
    .ReplyToAddress = strFrom              ' Optional, used when different than 'From' address
    .Subject = strSubject                  ' Optional
    .Message = strMessage                     ' Optional
'    .Attachment = Trim(txtAttach.Text)          ' Optional, separate multiple entries with delimiter character

    ' **************************************************************************
    ' Additional Optional properties, use as required by your application / environment
    ' **************************************************************************
'    .AsHTML = bHtml                             ' Optional, default = FALSE, send mail as html or plain text
'    .ContentBase = ""                           ' Optional, default = Null String, reference base for embedded links
'    .EncodeType = MyEncodeType                  ' Optional, default = MIME_ENCODE
'    .Priority = etPriority                      ' Optional, default = PRIORITY_NORMAL
'    .Receipt = bReceipt                         ' Optional, default = FALSE
'    .UseAuthentication = bAuthLogin             ' Optional, default = FALSE
'    .UsePopAuthentication = bPopLogin           ' Optional, default = FALSE
'    .UserName = txtUserName                     ' Optional, default = Null String
'    .Password = txtPassword                     ' Optional, default = Null String, value is NOT saved
'    .POP3Host = txtPopServer
'    .MaxRecipients = 100                        ' Optional, default = 100, recipient count before error is raised
    
    ' **************************************************************************
    ' Advanced Properties, change only if you have a good reason to do so.
    ' **************************************************************************
    ' .ConnectTimeout = 10                      ' Optional, default = 10
    ' .ConnectRetry = 5                         ' Optional, default = 5
    ' .MessageTimeout = 60                      ' Optional, default = 60
    ' .PersistentSettings = True                ' Optional, default = TRUE
    ' .SMTPPort = 25                            ' Optional, default = 25

    ' **************************************************************************
    ' OK, all of the properties are set, send the email...
    ' **************************************************************************
    ' .Connect                                  ' Optional, use when sending bulk mail
    .Send                                       ' Required
    ' .Disconnect                               ' Optional, use when sending bulk mail
  End With
End Sub

Open in new window

Avatar of schmir1

ASKER

Not sure why I'm not catching the event.  What could I try now?
Avatar of schmir1

ASKER

I found out that I needed to set the mcMyMail to nothing before re-using it.  That was causing it to not work at all.  I got it working but with a kludge of using global flag and string.
You should set and reset the Class module each time you need it. I'm not sure why you're using a global flag for something of this nature - just do this:

Build a new instance of the class
Use that class
Destroy that instance

Avatar of schmir1

ASKER

Could you explain how to do this?

Is this build new instance?
  Set mcMyMail = New cSendMail

Is this destroy that instance?
      Set mcMyMail = Nothing
Avatar of schmir1

ASKER

Also, the global flag is needed because I could never figure out how to catch the signalled event?
ASKER CERTIFIED SOLUTION
Avatar of Scott McDaniel (EE MVE )
Scott McDaniel (EE MVE )
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of schmir1

ASKER

Great answer.  

That's what I was doing wrong.  I was trying to catch the event in a form that wasn't the same as the original module that created the object.  I need to move some code around to fix it the right way (as you described).