smtp.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. package main
  2. import (
  3. "bytes"
  4. "fmt"
  5. "html"
  6. "io/ioutil"
  7. "mime/quotedprintable"
  8. "net/smtp"
  9. "os"
  10. "strings"
  11. "time"
  12. "golang-fave/engine/mysqlpool"
  13. "golang-fave/engine/sqlw"
  14. "golang-fave/engine/wrapper/config"
  15. "golang-fave/utils"
  16. )
  17. func smtp_send(host, port, user, pass, subject, msg string, receivers []string) error {
  18. header := make(map[string]string)
  19. header["From"] = user
  20. header["To"] = strings.Join(receivers, ", ")
  21. header["Subject"] = subject
  22. header["MIME-Version"] = "1.0"
  23. header["Content-Type"] = fmt.Sprintf("%s; charset=\"utf-8\"", "text/html")
  24. header["Content-Transfer-Encoding"] = "quoted-printable"
  25. header["Content-Disposition"] = "inline"
  26. message := ""
  27. for key, value := range header {
  28. message += fmt.Sprintf("%s: %s\r\n", key, value)
  29. }
  30. var encodedMessage bytes.Buffer
  31. finalMessage := quotedprintable.NewWriter(&encodedMessage)
  32. finalMessage.Write([]byte(msg))
  33. finalMessage.Close()
  34. message += "\r\n" + encodedMessage.String()
  35. return smtp.SendMail(
  36. host+":"+port,
  37. smtp.PlainAuth("", user, pass, host),
  38. user,
  39. receivers,
  40. []byte(message),
  41. )
  42. }
  43. func smtp_prepare(db *sqlw.DB, conf *config.Config) {
  44. rows, err := db.Query(
  45. `SELECT
  46. id,
  47. email,
  48. subject,
  49. message
  50. FROM
  51. notify_mail
  52. WHERE
  53. status = 2
  54. ORDER BY
  55. id ASC
  56. ;`,
  57. )
  58. if err == nil {
  59. defer rows.Close()
  60. values := make([]string, 4)
  61. scan := make([]interface{}, len(values))
  62. for i := range values {
  63. scan[i] = &values[i]
  64. }
  65. for rows.Next() {
  66. err = rows.Scan(scan...)
  67. if err == nil {
  68. if _, err := db.Exec(
  69. `UPDATE notify_mail SET status = 3 WHERE id = ?;`,
  70. utils.StrToInt(string(values[0])),
  71. ); err == nil {
  72. go func(db *sqlw.DB, conf *config.Config, id int, subject, msg string, receivers []string) {
  73. if err := smtp_send(
  74. (*conf).SMTP.Host,
  75. utils.IntToStr((*conf).SMTP.Port),
  76. (*conf).SMTP.Login,
  77. (*conf).SMTP.Password,
  78. subject,
  79. msg,
  80. receivers,
  81. ); err == nil {
  82. if _, err := db.Exec(
  83. `UPDATE notify_mail SET status = 1 WHERE id = ?;`,
  84. id,
  85. ); err != nil {
  86. fmt.Printf("Smtp send error (sql, success): %v\n", err)
  87. }
  88. } else {
  89. if _, err := db.Exec(
  90. `UPDATE notify_mail SET error = ?, status = 0 WHERE id = ?;`,
  91. err.Error(),
  92. id,
  93. ); err != nil {
  94. fmt.Printf("Smtp send error (sql, error): %v\n", err)
  95. }
  96. }
  97. }(
  98. db,
  99. conf,
  100. utils.StrToInt(string(values[0])),
  101. html.EscapeString(string(values[2])),
  102. html.EscapeString(string(values[3])),
  103. []string{html.EscapeString(string(values[1]))},
  104. )
  105. } else {
  106. fmt.Printf("Smtp send error (sql, update): %v\n", err)
  107. }
  108. }
  109. }
  110. }
  111. }
  112. func smtp_process(dir, host string, mp *mysqlpool.MySqlPool) {
  113. db := mp.Get(host)
  114. if db != nil {
  115. conf := config.ConfigNew()
  116. if err := conf.ConfigRead(strings.Join([]string{dir, "config", "config.json"}, string(os.PathSeparator))); err == nil {
  117. if (*conf).SMTP.Host != "" && (*conf).SMTP.Login != "" && (*conf).SMTP.Password != "" {
  118. if err := db.Ping(); err == nil {
  119. smtp_prepare(db, conf)
  120. }
  121. }
  122. } else {
  123. fmt.Printf("Smtp error (config): %v\n", err)
  124. }
  125. }
  126. }
  127. func smtp_loop(www_dir string, stop chan bool, mp *mysqlpool.MySqlPool) {
  128. dirs, err := ioutil.ReadDir(www_dir)
  129. if err == nil {
  130. for _, dir := range dirs {
  131. select {
  132. case <-stop:
  133. break
  134. default:
  135. if mp != nil {
  136. target_dir := strings.Join([]string{www_dir, dir.Name()}, string(os.PathSeparator))
  137. if utils.IsDirExists(target_dir) {
  138. smtp_process(target_dir, dir.Name(), mp)
  139. }
  140. }
  141. }
  142. }
  143. }
  144. }
  145. func smtp_start(www_dir string, mp *mysqlpool.MySqlPool) (chan bool, chan bool) {
  146. ch := make(chan bool)
  147. stop := make(chan bool)
  148. go func() {
  149. for {
  150. select {
  151. case <-time.After(5 * time.Second):
  152. // Run every 5 seconds
  153. smtp_loop(www_dir, stop, mp)
  154. case <-ch:
  155. ch <- true
  156. return
  157. }
  158. }
  159. }()
  160. return ch, stop
  161. }
  162. func smtp_stop(ch, stop chan bool) {
  163. for {
  164. select {
  165. case stop <- true:
  166. case ch <- true:
  167. <-ch
  168. return
  169. case <-time.After(3 * time.Second):
  170. fmt.Println("Smtp error: force exit by timeout after 3 seconds")
  171. return
  172. }
  173. }
  174. }