Solved

Lotus Notes Error handling when emailing - can I catch invalid names?

Posted on 2007-11-28
13
3,054 Views
Last Modified: 2016-09-26
I have a script that sends mail based on a list of names in a document. The function that does the mail also creates new documents based on transactions entered by the user. Kind of a child document...

 The error I received "Unable to send Mail, No match found in address book" is valid because there was one person in the list who is no longer listed in the address book. But when it presented the error to the User, it also apparrently dropped out of the function it was in, without processing the other names and without processing the child doc.

I'm wondering if I can add some error handling so that the code can handle invalid names in the list. If I can trap for the error, I can have the code mail the Admin of the database about the missing name and (more importantly) let the user continue their work.

Function MailPurchAlert(Amount As Variant, note As notesdocument, Action As String)

	Dim workspace As New NotesUIWorkspace

	Dim session As New notessession

	Dim db As NotesDatabase

	Set db = session.CurrentDatabase 

	Dim item As NotesItem

	GROUP = note.MAILTO

	Set item = note.GetFirstItem("MAILTO")

	FUND = note.Fund(0)

	SETTLEDATE = Cstr(note.Date(0))

	Purchase = Cstr(note.Purchase(0))

	Redemption= Cstr(note.Redemption(0))

	Cancel = Cstr(note.Cancel_1(0))

	PurchaseOld = Cstr(note.Purchase_1(0))

	RedemptionOld= Cstr(note.Redemption_1(0))

	CancelOld = Cstr(note.Cancel_1(0))

	'Msgbox "purchalert"

	If Isempty(GROUP) Then

			' do nothing

	Else

			'Forall a In note.MAILTO

	'	Set item = note.getfirstitem("MAILTO")

		

		Set SendTo = New NotesName(a)

		Set NotifyDoc = New NotesDocument(Db)

		NotifyDoc.Form = "Memo"

		NotifyDoc.SendTo = SendTo.Abbreviated

		NotifyDoc.Subject = "A CHANGE to a Large $ Trade Notification"

		Set Body = New NotesRichTextItem(NotifyDoc, "Body")

		Msg =  "Please note that the " & FUND & " fund will have a large dollar " & Action & " trade in the amount of "

		Body.AppendText(Msg)

		Body.AddNewLine(1)

		Msg = Amount & " on Settlement Date of " & SETTLEDATE & ". This represents a change in what was reported to you."

		Body.AppendText (Msg)

		Body.AddNewLine(2)

		Body.AppendText "To view more information regarding this large dollar trade notification, please review the "

		Body.AddNewLine(1)

		Body.AppendText "Summary page of the Large $ Trade Notification database. "

		Body.AddNewLine(2)

		Body.AppendText "Click here to go to the document: "

		Body.AppendDocLink Note, "Large Dollar"

		Body.AddNewLine(2)

		Body.AppendText "For questions regarding this trade notice, please contact the individual that submitted this notice via the Large Dollar Trade Notification database."	

		Body.AddNewLine(2)

		Body.AppendText " For questions about the database, please contact your Admin."	

	End If

	For x=0 To Ubound(item.values)

		Call notifyDoc.Send(False,item.values(x))

		Print "Mail Send to: "&Cstr(item.values(x))

	Next

				'NotifyDoc.Send False

			'End Forall

	

End Function

Open in new window

0
Comment
Question by:BillTr
13 Comments
 
LVL 22

Accepted Solution

by:
Bill-Hanson earned 500 total points
ID: 20369587
Are you familiar with the "On Error" statement?  That is how we trap errors in LotusScript.  I forget what the error code is for "Unable to send Mail...", but if you find that code, you could place a trap like this at the top of your code...

On Error XXXX Goto CATCH_MAIL_SEND

... Where XXXX is the error code to trap.  Then, at the end of your code you would explicitly call Exit Function, and add a label that defines an error handler block...

    Exit Function

CATCH_MAIL_SEND:
    Msgbox "Unable to send email"
    Resume next.

The good news is that you don't really need to know the error code.  You can wrap a single line or group of lines in a trap.  Here is an example.  I'll leave the error email notification part to you, but it would replace the msgbox in the error trap section.


Function MailPurchAlert(Amount As Variant, note As notesdocument, Action As String)

	Dim workspace As New NotesUIWorkspace

	Dim session As New notessession

	Dim db As NotesDatabase

	Set db = session.CurrentDatabase 

	Dim item As NotesItem

	GROUP = note.MAILTO

	Set item = note.GetFirstItem("MAILTO")

	FUND = note.Fund(0)

	SETTLEDATE = Cstr(note.Date(0))

	Purchase = Cstr(note.Purchase(0))

	Redemption= Cstr(note.Redemption(0))

	Cancel = Cstr(note.Cancel_1(0))

	PurchaseOld = Cstr(note.Purchase_1(0))

	RedemptionOld= Cstr(note.Redemption_1(0))

	CancelOld = Cstr(note.Cancel_1(0))

	'Msgbox "purchalert"

	If Isempty(GROUP) Then

			' do nothing

	Else

			'Forall a In note.MAILTO

	'	Set item = note.getfirstitem("MAILTO")

		

		Set SendTo = New NotesName(a)

		Set NotifyDoc = New NotesDocument(Db)

		NotifyDoc.Form = "Memo"

		NotifyDoc.SendTo = SendTo.Abbreviated

		NotifyDoc.Subject = "A CHANGE to a Large $ Trade Notification"

		Set Body = New NotesRichTextItem(NotifyDoc, "Body")

		Msg =  "Please note that the " & FUND & " fund will have a large dollar " & Action & " trade in the amount of "

		Body.AppendText(Msg)

		Body.AddNewLine(1)

		Msg = Amount & " on Settlement Date of " & SETTLEDATE & ". This represents a change in what was reported to you."

		Body.AppendText (Msg)

		Body.AddNewLine(2)

		Body.AppendText "To view more information regarding this large dollar trade notification, please review the "

		Body.AddNewLine(1)

		Body.AppendText "Summary page of the Large $ Trade Notification database. "

		Body.AddNewLine(2)

		Body.AppendText "Click here to go to the document: "

		Body.AppendDocLink Note, "Large Dollar"

		Body.AddNewLine(2)

		Body.AppendText "For questions regarding this trade notice, please contact the individual that submitted this notice via the Large Dollar Trade Notification database."	

		Body.AddNewLine(2)

		Body.AppendText " For questions about the database, please contact your Admin."	

	End If

	For x=0 To Ubound(item.values)

		On Error Goto CATCH_SEND_ERROR ' Set a wildcard trap.

		Call notifyDoc.Send(False,item.values(x))

		On Error Goto 0 ' Remove the wildcard trap.

		Print "Mail Send to: "&Cstr(item.values(x))

	Next

				'NotifyDoc.Send False

			'End Forall

	Exit Function ' So we don't pass through into our error handler.

	

CATCH_SEND_ERROR:

	msgbox "Unable to send email to " & item.values(x) & "."

	Resume Next ' Keep processing.  You could also "Exit Function" or "End" here to stop processing.

	

End Function

Open in new window

0
 

Author Comment

by:BillTr
ID: 20370175
This is very helpful!
Can I leverage this to skp the name? Say I had the GOTO jump to right before the next statement...to force it to keep processing from there..?

The problem is that I drop out of the code when I hit the bad name, when what I want it to do is skip that name and go on to the next. (I've been experimenting with some code to check the name against the address books first, but it does slow things down. I'm still trying to get that to work.)
0
 
LVL 22

Expert Comment

by:Bill-Hanson
ID: 20374093
The code I posted already skips the name and continues to send emails.

Here's what happens...

(1) In the For loop, the On Error statement on line 48 sets a trap to catch for all errors.
(2) If notifyDo.Send on line 49 raises an error, the code will automatically jump to the CATCH_SEND_ERROR label on line 57.
(3) The example displays the error in a message box on line 58, but you should actually handle the error instead of just displaying it.
(4) When the code reaches line 59, the Resume Next statement causes the code to jump to the line immediately following the one that caused the error (line 50).
(5) The On Error statement on line 50 removes the trap (setting the Goto to zero removes a trap).
(6) The For loop continues to execute, sending emails until the end of the array (item.values) is reached.
(7) The "Exit Function" on line 55 exits he function normally and prevents the code from accidentally entering the CATCH_SEND_ERROR block.

This was just an example of setting an error trap for a single line of code regardless of the actual error raised.  We can improve this by finding out what the error code is for an "Unable to send mail" error.  In LotusScript, there are a few functions that tell you information about the error:

Err - Contains the error code.
Error$ - Contains the error message.
Erl - Contains the line number where the error occurred.

You can also define and throw your own errors with the "Error" statement.  All you do is pass an error code and message.  Lotus uses error codes in these ranges 0-323, 4000-4697 , and 13000-13019.  They are defined in the files "lserr.lss", "lsxbeerr.lss", and "lsuierr.lss".  I use the range 2000-3999 for my custom errors.  Here's an example.  Say you want to provide a better error message that the default "Object varible not set".  Here's how you could do it with the Error statement:

set doc = view.GetDocumentByKey("SOMEKEY", True)
if (doc is nothing) Error 2000, "Unable to locate the SOMEKEY document!"
doc.SomeField = ""

I like this better then using Msgbox and Exit Function because it fits on a single line.   :)

Anyway, back to our send email problem.  We want to improve the error handling in our first script, so we need to know the error code for "Unable to send mail".  If you look in lsxbeerr, you'll see that lsERR_NOTES_NO_MATCH =  4294, but that is kind of hard to determine just from reading the file, so here's a simple agent that will tell us the error code.  We'll use this error code (4294) in our next example.
Sub Initialize

	

	On Error Goto CATCH

	Dim sess As New NotesSession()

	Dim db As NotesDatabase

	Dim doc As NotesDocument

	Set db = sess.CurrentDatabase

	Set doc = db.CreateDocument()

	doc.Form = "Memo"

	doc.Subject = "Checking Error Code"

	Call doc.Send(False, "CN=Bad Name/O=Bad Org")

	Exit Sub

CATCH:

	Msgbox "Error " & Cstr(Err) & " on line " & Cstr(Erl) & Chr(10) & Error$

	End

	

End Sub

Open in new window

0
 

Author Comment

by:BillTr
ID: 20374650
Perfect! Thanks!
0
 

Author Closing Comment

by:BillTr
ID: 31411547
Exactly what I was looking for!
0
 
LVL 22

Expert Comment

by:Bill-Hanson
ID: 20374719
No problem.  Here's another example that keeps an array of failures, then sends a single email to an administrator containing all of the names.  Also, I've added a specific error trap so that we avoid setting and clearing the single line trap.

Function MailPurchAlert(Amount As Variant, note As notesdocument, Action As String)
      
      On Error 4294 Goto CATCH_SEND_ERROR ' Set up a trap to catch only lsERR_NOTES_NO_MATCH errors.
      Dim workspace As New NotesUIWorkspace
      Dim session As New notessession
      Dim db As NotesDatabase
      Set db = session.CurrentDatabase
      Dim item As NotesItem
      GROUP = note.MAILTO
      Set item = note.GetFirstItem("MAILTO")
      FUND = note.Fund(0)
      SETTLEDATE = Cstr(note.Date(0))
      Purchase = Cstr(note.Purchase(0))
      Redemption= Cstr(note.Redemption(0))
      Cancel = Cstr(note.Cancel_1(0))
      PurchaseOld = Cstr(note.Purchase_1(0))
      RedemptionOld= Cstr(note.Redemption_1(0))
      CancelOld = Cstr(note.Cancel_1(0))
      
      If (Not Isempty(GROUP)) Then
            Set SendTo = New NotesName(a)
            Set NotifyDoc = New NotesDocument(Db)
            NotifyDoc.Form = "Memo"
            NotifyDoc.SendTo = SendTo.Abbreviated
            NotifyDoc.Subject = "A CHANGE to a Large $ Trade Notification"
            Set Body = New NotesRichTextItem(NotifyDoc, "Body")
            Msg = "Please note that the " & FUND & " fund will have a large dollar " & Action & " trade in the amount of "
            Body.AppendText(Msg)
            Body.AddNewLine(1)
            Msg = Amount & " on Settlement Date of " & SETTLEDATE & ". This represents a change in what was reported to you."
            Body.AppendText (Msg)
            Body.AddNewLine(2)
            Body.AppendText "To view more information regarding this large dollar trade notification, please review the "
            Body.AddNewLine(1)
            Body.AppendText "Summary page of the Large $ Trade Notification database. "
            Body.AddNewLine(2)
            Body.AppendText "Click here to go to the document: "
            Body.AppendDocLink Note, "Large Dollar"
            Body.AddNewLine(2)
            Body.AppendText "For questions regarding this trade notice, please contact the individual that submitted this notice via the Large Dollar Trade Notification database."      
            Body.AddNewLine(2)
            Body.AppendText " For questions about the database, please contact your Admin."      
      End If
      
      Dim failures As Variant ' Use an array to save the names that failed to send.
      Dim userName As String ' Save the name so that the error block can see it (the error block would know what item.values was, but not x).
      For x=0 To Ubound(item.values)
            userName = item.values(x)
            Call notifyDoc.Send(False, userName)
            Print "Mail Send to: " & Cstr(userName)
      Next
      
      ' Check the failures array.
      If (Isarray(failures)) Then
            Dim ErrorDoc As NotesDocument
            Set ErrorDoc = Db.CreateDocument()
            ErrorDoc.Form = "Memo"
            ErrorDoc.Subject = "Errors from " & Db.Title
            ErrorDoc.SendTo = "Your DB Admin"
            Dim txtBody As String
            txtBody = "Unable to send email to the following users:" & Chr(10)
            Forall v In failures
                  txtBody = txtBody & v
            End Forall
            ErrorDoc.Body = txtBody
            Call ErrorDoc.Send(False)
      End If
      Exit Function ' So we don't pass through into our error handler.
      
CATCH_SEND_ERROR:
      If (Isarray(failures)) Then Redim failures(Ubound(failures)) Else      Redim failures(0) ' Init or expand the array.
      failures(Ubound(failures)) = userName ' Set the last element of the array to the user's name.
      Resume Next ' Keep processing.  You could also "Exit Function" or "End" here to stop processing.
      
End Function
0
Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

 
LVL 31

Expert Comment

by:qwaletee
ID: 20378229
By the way, there is another way to do a single-line error trap.  You have:

            On Error Goto CATCH_SEND_ERROR ' Set a wildcard trap.
            Call notifyDoc.Send(False,item.values(x))
            On Error Goto 0 ' Remove the wildcard trap.


Instead, you should do it as follows:
            On Error Resume Next ' Set a wildcard trap.
            Call notifyDoc.Send(False,item.values(x))
            On Error Goto 0 ' Remove the wildcard trap.
            If Err <> 0 Then
                  If (Isarray(failures)) Then Redim Preserve failures(Ubound(failures)+1) Else Redim failures(0)
                  failures(Ubound(failures)) = userName ' Set the last element of the array to the user's name.
                  Err = 0 'resets the status of the error, since there is no RESUME in this format
            End If
0
 
LVL 22

Expert Comment

by:Bill-Hanson
ID: 20381901
Hey, good point.

Also, you re-dimmed your array correctly!  Redim Preserve failures(Ubound(failures)+1)

I must have been thinking in JavaScript again.  failures[failures.length] = "new element"

Oops!
0
 

Author Comment

by:BillTr
ID: 20453696
Can't I use On Error more than once? In another program I have the users drop and add personal views.
The views are dropped via a .remove and that will fail with an object not set if the view in question has
already been removed.

So, I inserted the on error to send the user a popup msg when the view is already gone. This works fine on the first view, but fails if it encounters the error on the next.

I'm attaching the code, but be kind, I realize I should rewrite the whole thing but I just want to understand why it's failing here. Thanks

This is the second STEP,,,the first one worked the same way. IF the first step processes on error then the second step will fail to.


  ' ***********************************************************************************************************

     ' If ret% <> 2 Then          

        '  ret% = Msgbox(" Delete your Private view called Dashboard\2. Current Work.  Continue? ", 3 + 16, "No Data Entered")

		Set view = db.GetView( "My Dashboard\2. Current Work" ) 

    '      Msgbox ret%

          'If ret% = 6 Then

     ' make sure they are deleting the personal view, not actual design element

' Then remove the view, try using error2 instead of on error

		On Error2 Goto CATCH_CURRENTWORK_ERROR ' Set a wildcard trap.

		If Not(Isempty(view.Readers)) Then

			Call view.Remove 

			

                '    Msgbox "The Current Work view has been updated. You must close and re-open the database before you will see the changes"

		End If

		On Error Goto 0 ' Remove the wildcard trap.

		Goto FIN_CURRENTWORK  ' skip error and continue on

CATCH_CURRENTWORK_ERROR:

		Messagebox "It looks like the Current Work view is up to date or has already been removed. "

		On Error Goto 0 ' Remove the wildcard trap.

		

FIN_CURRENTWORK:

Open in new window

0
 
LVL 22

Expert Comment

by:Bill-Hanson
ID: 20457034
I must say that I don't like placing error traps inline with the main code block, but there's nothing syntactically wrong with doing so.  I prefer placing all of the traps at the end of the function.  It makes things much easier to read.  Also, the result of trapping an error should end with a Resume or Exit call.  In your code above, there are several statements that don't make sense.

Line 9:  On Error2 Goto CATCH_CURRENTWORK_ERROR ' Set a wildcard trap.
Since you specified an error code, this is not a wildcard trap.  It will only trap errors with a code of 'Error2'.  I assume that is just an error in the comment.

Line 15: On Error Goto 0 ' Remove the wildcard trap.
Why? This line does remove the wildcard trap, but none was set.

Line 16: Goto FIN_CURRENTWORK  ' skip error and continue on
Error traps should not be setup like standard blocks that you can just skip or execute (more on this below).  Also, using GOTO makes the code hard to read and results in 'spaghetti' code.  The general rule of thumb is: "If you can't find a way to do without a GOTO statement, you need to move some code to a new function".  That said, we have to deal with 'some' GOTO statements due to LS's limited error handling capabilities (ie: no try..catch constructs).

Line 19: On Error Goto 0 ' Remove the wildcard trap.
Again, there is no wildcard trap set.  Also, this is not the right way to recover from an error.  You need to use a Resume or Exit statement.

The 'Resume' keyword is how you recover from an error.  Not only does it send the code pointer to a specific location, but it also clears the error status flags (Err, Error$, Erl).  It takes one of three parameters:

Resume 0
This will automatically send the code pointer back to execute the same line that caused the error.
This is handy when you can fix the problem and want to try again.

Resume Next
This will automatically send the code pointer back to execute the line directly after the one that caused the error.  This is handy when you can recover from the error in the error handler block and want to continue processing anyway.

Resume LABEL
This will send the code pointer to any label you define.  This is probably what you want to use in your code above.

Here is how I would re-write this block of code:

Sub YourSub()
 

	' 

	' Your code before the block you posted...

	' 

	Set view = db.GetView( "My Dashboard\2. Current Work" )

	On Error2 Goto CATCH_CURRENTWORK_ERROR ' Trap errors caused by view.Remove.

	If Not(Isempty(view.Readers)) Then

		Call view.Remove

	End If

	'

	' Contune processing your code...

	'

	Exit Sub

	

CATCH_CURRENTWORK_ERROR:

	Messagebox "It looks like the Current Work view is up to date or has already been removed. "

	Resume Next

	

End Sub

Open in new window

0
 

Author Comment

by:BillTr
ID: 20457048
The error seems tied to Notes having problems dealing with a view that does not exist. Why it works on the first occurance but fails on the rest is the issue. I experimented with checking for the existance of
the view first. There was another post here that dealt with a similar issue when trying to run an archive.

Anyway, long story-short, I inserted the attached if statement and got the code to work.
On Error Goto CATCH_ACTIONITEM_ERROR ' Set a wildcard trap.

		'If Not(Isempty(view.Readers)) Then <-- this fails

		If view Is Nothing Then   ' <-- this works

			Goto CATCH_ACTIONITEM_ERROR

		Else

			Call view.Remove 

		End If

		

               ' Msgbox "The Action Items view has been updated. You must close and re-open the database before you will see the changes"

		'End If			

		On Error Goto 0 ' Remove the wildcard trap.

		

		Goto FIN_ACTIONITEM  ' skip error and continue on

		

CATCH_ACTIONITEM_ERROR :

		Messagebox "I think the Action Items view is up to date or has already been removed. "

		On Error Goto 0 ' Remove the wildcard trap.

		

FIN_ACTIONITEM:

Open in new window

0
 
LVL 22

Expert Comment

by:Bill-Hanson
ID: 20457233
The reason that it is not trapping subsequent errors is line 18.   You're removing all error traps on the first error.
0
 

Expert Comment

by:Nick Golomysov
ID: 41816963
Have a look at the error handling here: https://github.com/dev-ng/ls-dl
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Suggested Solutions

I thought it will be a good idea to make a post as it will help in case someone else faces these issues. I trust this gives an idea how each entry in Notes.ini can mean a lot for the Domino Server to be functioning properly. This article discusses t…
For beginners of Lotus Notes user this is important to know about the types of files and their location supported by IBM Notes. Mostly users are unaware about how many file types are created and what their usages are. This Article is fully dedicated…
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now