In this TSNotify Series 3, we will learn how to trigger real-time email notification based on the Windows Task Scheduler Event ID. This is important for any critical software that relies on it's scheduling from the Windows Task Scheduler, when it failed to run this application, then the TSNotify will notify any of the recipients from the config.YAML via email for their action with step by step guide in Golang programming language.
#MaharlikansCode
#TSNotifySeries3
#TaskSchedulerEventIDNotify
#LifeAsSoftwareDeveloper
#Maharlikans
#FilipinoSoftwareDeveloper
If you go with extra mile for buying me a cup of coffee, I appreciate it guys: https://ko-fi.com/maharlikanscode
Source Codes:
package cmd
import (
"fmt"
"os"
"strings"
"tsnotify/config"
"github.com/common-nighthawk/go-figure"
"github.com/fatih/color"
"github.com/fsnotify/fsnotify"
"github.com/itrepablik/itrlog"
"github.com/mitchellh/go-homedir"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
const (
_smtpPort = 25 // set default as port number 25
_emailTemplateEvent = "event"
_emailTemplateTask = "task"
_emailTimeExtraLetter = "Z"
_dateTimeFormat = "January 02 2006 03:04:05 PM"
)
// SMStatus stores the email broadcasting status for each triggered events
type SMStatus struct {
TaskName, TaskNextRunTime, TaskStatus string
Recipients []string
IsSent bool
}
// ST map collection type structure to format accepting parameters
type ST map[string]interface{}
// SMStat uses the map to store in memory about keeping the email broadcasted status info
type SMStat struct {
Status map[string][]byte
}
var cfgFile string
var hostName string
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: strings.ToLower(config.AppName),
Short: config.AppDesc,
Long: config.AppDesc,
Version: "1.0.0",
// Uncomment the following line if your bare application
// has an action associated with it:
// Run: func(cmd *cobra.Command, args []string) { },
}
// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
// initConfig reads in config file and ENV variables if set.
func initConfig() {
if cfgFile != "" {
// Use config file from the flag.
viper.SetConfigFile(cfgFile)
} else {
// Find home directory.
home, err := homedir.Dir()
if err != nil {
color.Red(err.Error())
itrlog.Error(err)
os.Exit(1)
}
// Search config in home directory with name ".tsnotify" (without extension).
viper.AddConfigPath(home)
viper.SetConfigName(".tsnotify")
}
viper.AutomaticEnv() // read in environment variables that match
// If a config file is found, read it in.
if err := viper.ReadInConfig(); err == nil {
color.Red("Using config file: " + viper.ConfigFileUsed())
}
}
func init() {
hostName, _ = os.Hostname()
// Display the app ASCII logo
myFigure := figure.NewFigure(config.AppDisplayName, "", true)
myFigure.Print()
cobra.OnInitialize(initConfig)
viper.SetConfigName("config")
viper.AddConfigPath(".")
if err := viper.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
// Config file not found; create the "config.yaml" asap.
f, err := os.OpenFile("config.yaml", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
itrlog.Fatalf("error opening file: %v", err)
}
defer f.Close()
} else {
// Config file was found but another error was produced
itrlog.Fatalf("fatal error config file: %v", err)
}
}
LoadViperCofig()
viper.WatchConfig() // Tell the viper to watch any new changes to the config file.
viper.OnConfigChange(func(e fsnotify.Event) {
fmt.Println("Config file changed:", e.Name)
itrlog.Warn("Config file changed:", e.Name)
LoadViperCofig()
})
}
// LoadViperCofig reads the viper 'config.yaml' file
func LoadViperCofig() {
cobra.OnInitialize(initConfig)
viper.SetConfigName("config") // name of config file (without extension)
viper.AddConfigPath(".") // optionally look for config in the working directory
// Handle errors reading the config file
if err := viper.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
// Config file not found; create the "config.yaml" asap.
f, err := os.OpenFile("config.yaml", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
itrlog.Fatalf("error opening file: %v", err)
}
defer f.Close()
} else {
// Config file was found but another error was produced
itrlog.Fatalf("fatal error config file: %v", err)
}
}
}