go to post Tony Marnell · Sep 22, 2023 I use the NotifyBecomePrimary() hook in the ZMIRROR routine to call some code to send an email. Here's the ZMIRROR routine from the %SYS namespace: ZMIRROR // User-defined code for mirror environment events QUIT // // The member has fully become primary so it is now safe to job off processes // // 20230314 - TM - Initial version // NotifyBecomePrimary() // // Send an alert email to notify support staff that a mirror failover has occurred // // 20230726 - TM - Initial version // set Namespace = $znspace try { znspace "HAPPI" do ##class(System.AlertEmail).MirrorFailover() znspace Namespace } catch { znspace Namespace } QUIT The email-sending code from the application namespace references configuration data in a global and constructs a html-formatted message to inform interested parties that a mirror failover has occurred. You should be able to make out what's going on and get it working to your own needs. Here's the class: /// Description /// ----------- /// /// Grapevine Solutions - HAPPI /// /// This class implements the alert email methods for various system events. /// /// Revision History /// ---------------- /// /// 20230726 - TM - Initial version /// Class System.AlertEmail Extends %RegisteredObject { /// This method sends an alert email message when a mirror failover occurs. It is called from /// the ZMIRROR routine in the %SYS namespace. /// /// Revision History /// ---------------- /// /// 20230726 - TM - Initial version /// ClassMethod MirrorFailover() { // get the current time set EmailTimeStampH = $now() // get the hostname, e.g. HCPGPO11-V, HCDDMC11-V set HostName = $zconvert($SYSTEM.INetInfo.LocalHostName(), "U") // get the environment, e.g. LIVE, TEST, DEV set Environment = ^HAPPIConfig("HostName", HostName) // get a connection to the email server set MailServer = ##class(%Net.SMTP).%New() set MailServer.smtpserver = ^HAPPIConfig("Environment", Environment, "Email", "SMTPServer") set MailServer.port = ^HAPPIConfig("Environment", Environment, "Email", "SMTPPort") // check for email server authentication details set MailServerUserName = $get(^HAPPIConfig("Environment", Environment, "Email", "Authentication", "UserName")) set MailServerPassword = $get(^HAPPIConfig("Environment", Environment, "Email", "Authentication", "Password")) // if there are authentication details then add them to the connection if ((MailServerUserName '= "") & (MailServerPassword '= "")) { set MailAuthentication = ##class(%Net.Authenticator).%New() set MailAuthentication.UserName = MailServerUserName set MailAuthentication.Password = MailServerPassword set MailServer.authenticator = MailAuthentication } // create a new HTML-formatted mail message set MailMessage = ##class(%Net.MailMessage).%New() set MailMessage.IsHTML = 1 // set the recipient list set To = $order(^HAPPIConfig("Environment", Environment, "Email", "To", "")) while (To '= "") { if (^HAPPIConfig("Environment", Environment, "Email", "To", To) = 1) do MailMessage.To.Insert(To) set To = $order(^HAPPIConfig("Environment", Environment, "Email", "To", To)) } // set the sender set MailMessage.From = ^HAPPIConfig("Environment", Environment, "Email", "From") // set the subject set Subject = "Mirror Failover Alert on " _ HostName _ " (" _ Environment _ ")" set MailMessage.Subject = Subject //-------------------------------- // build the message html document //-------------------------------- // start of html document do MailMessage.TextData.WriteLine("<!DOCTYPE html>") do MailMessage.TextData.WriteLine("<html>") // start of header do MailMessage.TextData.WriteLine("<head>") do MailMessage.TextData.WriteLine("<meta charset=""UTF-8"">") do MailMessage.TextData.WriteLine("<title>" _ Subject _ "</title>") // style sheet do MailMessage.TextData.WriteLine("<style>") do MailMessage.TextData.WriteLine("body {font-family: Arial, Helvetica, sans-serif;}") do MailMessage.TextData.WriteLine("h2 {color: blue; font-size: '125%';}") do MailMessage.TextData.WriteLine("h3 {color: blue; font-size: '100%';}") do MailMessage.TextData.WriteLine("table {border: 1px solid #ddd; border-spacing: 10px; border-collapse: separate;}") do MailMessage.TextData.WriteLine(".good {color: green;}") do MailMessage.TextData.WriteLine(".bad {color: red;}") do MailMessage.TextData.WriteLine("</style>") // end of header do MailMessage.TextData.WriteLine("</head>") // start of body do MailMessage.TextData.WriteLine("<body>") // write subject as message header do MailMessage.TextData.WriteLine("<h2>" _ Subject _ "</h2>") // write alert details do MailMessage.TextData.WriteLine("<h3>Alert Details</h3>") do MailMessage.TextData.WriteLine("<table>") do MailMessage.TextData.WriteLine("<tr>") do MailMessage.TextData.WriteLine("<td>Application</td>") do MailMessage.TextData.WriteLine("<td>HAPPI</td>") do MailMessage.TextData.WriteLine("</tr>") do MailMessage.TextData.WriteLine("<tr class=""bad"">") do MailMessage.TextData.WriteLine("<td>Alert Reason</td>") do MailMessage.TextData.WriteLine("<td>Mirror Failover") do MailMessage.TextData.WriteLine("</tr>") do MailMessage.TextData.WriteLine("<tr>") do MailMessage.TextData.WriteLine("<td>Host Name</td>") do MailMessage.TextData.WriteLine("<td>" _ HostName _ "</td>") do MailMessage.TextData.WriteLine("</tr>") do MailMessage.TextData.WriteLine("<tr>") do MailMessage.TextData.WriteLine("<td>Environment</td>") do MailMessage.TextData.WriteLine("<td>" _ Environment _ "</td>") do MailMessage.TextData.WriteLine("</tr>") do MailMessage.TextData.WriteLine("<tr>") do MailMessage.TextData.WriteLine("<td>Alert Time</td>") do MailMessage.TextData.WriteLine("<td>" _ $zdatetime($System.Util.UTCtoLocalWithZTIMEZONE(EmailTimeStampH), 3, 1, 3) _ "</td>") do MailMessage.TextData.WriteLine("</tr>") do MailMessage.TextData.WriteLine("</table>") // write support instructions do MailMessage.TextData.WriteLine("<h3>Support Instructions</h3>") do MailMessage.TextData.WriteLine("<p>") do MailMessage.TextData.WriteLine("A mirror failover has occurred in the " _ Environment _ " environment and " _ HostName _ " is now the primary failover member.") do MailMessage.TextData.WriteLine("</p>") do MailMessage.TextData.WriteLine("<p>") do MailMessage.TextData.WriteLine("Please ensure that the failover has not disrupted any application processes.") do MailMessage.TextData.WriteLine("</p>") do MailMessage.TextData.WriteLine("<p>") do MailMessage.TextData.WriteLine("Please do not reply to this message as it was automatically generated.") do MailMessage.TextData.WriteLine("</p>") // end of body do MailMessage.TextData.WriteLine("</body>") // end of html document do MailMessage.TextData.WriteLine("</html>") // send the message do MailServer.Send(MailMessage) QUIT } }
go to post Tony Marnell · Dec 9, 2015 At Grapevine Solutions we have successfully implemented a project for one of our Caché customers who had a requirement to add barcodes to some legacy character-based reports. This requirement meant moving to a modern reporting format with page-layout and graphics capabilities, along with support for generating barcodes. We provided a custom solution using Caché and some third-party development tools that reproduced new versions of the reports in PDF format alongside the current reports. Both versions of the reports are created from the existing menu option within the legacy character-based application. Additionally, the new report layouts can be easily modified by non-developers if needed. If you think our services would be of benefit to you please feel free to contact us.