smtpn.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. package smtpn
  2. /*
  3. SMTP Notifaiction Agent
  4. This is the mail sending agent for sending notification to user
  5. */
  6. import (
  7. "encoding/json"
  8. "errors"
  9. "io/ioutil"
  10. "log"
  11. "net/smtp"
  12. "strconv"
  13. "time"
  14. "github.com/valyala/fasttemplate"
  15. notification "imuslab.com/arozos/mod/notification"
  16. )
  17. type Agent struct {
  18. Hostname string `json:"-"`
  19. SMTPSenderDisplayName string
  20. SMTPSender string
  21. SMTPPassword string
  22. SMTPDomain string
  23. SMTPPort int
  24. UsernameToEmail func(string) (string, error) `json:"-"`
  25. }
  26. func NewSMTPNotificationAgent(hostname string, configFile string, usernameToEmailFunction func(string) (string, error)) (*Agent, error) {
  27. config, err := ioutil.ReadFile(configFile)
  28. if err != nil {
  29. return nil, errors.New("Unable to load config from file: " + err.Error())
  30. }
  31. //Pasre the json file to agent object
  32. newAgent := Agent{}
  33. err = json.Unmarshal(config, &newAgent)
  34. if err != nil {
  35. return nil, errors.New("Unable to parse config file for SMTP authentication")
  36. }
  37. newAgent.Hostname = hostname
  38. newAgent.UsernameToEmail = usernameToEmailFunction
  39. return &newAgent, nil
  40. }
  41. //Generate an empty config filepath
  42. func GenerateEmptyConfigFile(configFilepath string) error {
  43. demoConfig := Agent{}
  44. //Stringify the empty struct
  45. js, err := json.MarshalIndent(demoConfig, "", " ")
  46. if err != nil {
  47. return err
  48. }
  49. //Write to file
  50. err = ioutil.WriteFile(configFilepath, js, 0775)
  51. return err
  52. }
  53. func (a Agent) Name() string {
  54. return "smtpn"
  55. }
  56. func (a Agent) Desc() string {
  57. return "Notify user throught email"
  58. }
  59. func (a Agent) IsConsumer() bool {
  60. return true
  61. }
  62. func (a Agent) IsProducer() bool {
  63. return false
  64. }
  65. func (a Agent) ConsumerNotification(incomingNotification *notification.NotificationPayload) error {
  66. //Get a notification and send it out
  67. //Analysis the notification, get the target user's email
  68. userEmails := [][]string{}
  69. for _, username := range incomingNotification.Receiver {
  70. userEmail, err := a.UsernameToEmail(username)
  71. if err == nil {
  72. userEmails = append(userEmails, []string{username, userEmail})
  73. } else {
  74. log.Println("[SMTP Notification] Unable to notify " + username + ": Email not set")
  75. }
  76. }
  77. //For each user, send out the email
  78. for _, thisEntry := range userEmails {
  79. thisUser := thisEntry[0]
  80. thisEmail := thisEntry[1]
  81. //Load email template
  82. template, _ := ioutil.ReadFile("system/www/smtpn.html")
  83. t := fasttemplate.New(string(template), "{{", "}}")
  84. s := t.ExecuteString(map[string]interface{}{
  85. "receiver": "Hello " + thisUser + ",",
  86. "message": incomingNotification.Message,
  87. "sender": incomingNotification.Sender,
  88. "hostname": a.Hostname,
  89. "timestamp": time.Now().Format("2006-01-02 3:4:5 PM"),
  90. })
  91. msg := []byte("To: " + thisEmail + "\n" +
  92. "From: " + a.SMTPSenderDisplayName + " <" + a.SMTPSender + ">\n" +
  93. "Subject: " + incomingNotification.Title + "\n" +
  94. "MIME-version: 1.0;\nContent-Type: text/html; charset=\"UTF-8\";\n\n" +
  95. s + "\n\n")
  96. //Login to the SMTP server
  97. auth := smtp.PlainAuth("", a.SMTPSender, a.SMTPPassword, a.SMTPDomain)
  98. err := smtp.SendMail(a.SMTPDomain+":"+strconv.Itoa(a.SMTPPort), auth, a.SMTPSender, []string{thisEmail}, msg)
  99. if err != nil {
  100. log.Println("[SMTPN] Email sent failed: ", err.Error())
  101. return err
  102. }
  103. }
  104. return nil
  105. }
  106. func (a Agent) ProduceNotification(producerListeningEndpoint *notification.AgentProducerFunction) {
  107. return
  108. }