A temporary email service written in Go.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

107 lignes
2.3 KiB

  1. package mail
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io"
  6. "io/ioutil"
  7. "log"
  8. "mime"
  9. "mime/multipart"
  10. "net"
  11. "net/mail"
  12. "os"
  13. "strings"
  14. "github.com/mhale/smtpd"
  15. "github.com/thebaer/burner/validate"
  16. )
  17. var (
  18. mailInfo *log.Logger
  19. mailError *log.Logger
  20. )
  21. type MailConfig struct {
  22. Port int
  23. Host string
  24. }
  25. var mailCfg *MailConfig
  26. func Serve(host string, port int) error {
  27. mailCfg = &MailConfig{
  28. Port: port,
  29. Host: host,
  30. }
  31. // Set up variables
  32. mailInfo = log.New(os.Stdout, "", log.Ldate|log.Ltime)
  33. mailError = log.New(os.Stderr, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile)
  34. // Start mail server
  35. mailInfo.Printf("Starting %s mail server on :%d", mailCfg.Host, mailCfg.Port)
  36. err := smtpd.ListenAndServe(fmt.Sprintf(":%d", mailCfg.Port), mailHandler, mailCfg.Host, mailCfg.Host)
  37. if err != nil {
  38. mailError.Printf("Couldn't start mail server: %v", err)
  39. return err
  40. }
  41. return nil
  42. }
  43. func mailHandler(origin net.Addr, from string, to []string, data []byte) {
  44. msg, err := mail.ReadMessage(bytes.NewReader(data))
  45. if err != nil {
  46. mailError.Printf("Couldn't read email message: %v", err)
  47. return
  48. }
  49. var content []byte
  50. subject := msg.Header.Get("Subject")
  51. contentType, params, err := mime.ParseMediaType(msg.Header.Get("Content-Type"))
  52. if err != nil {
  53. mailError.Printf("Couldn't parse Content-Type: %v", err)
  54. }
  55. if strings.HasPrefix(contentType, "multipart/") {
  56. mr := multipart.NewReader(msg.Body, params["boundary"])
  57. for {
  58. p, err := mr.NextPart()
  59. if err == io.EOF {
  60. break
  61. }
  62. if err != nil {
  63. mailError.Printf("Error getting NextPart(): %v", err)
  64. continue
  65. }
  66. if !strings.HasPrefix(p.Header.Get("Content-Type"), "text/plain") {
  67. continue
  68. }
  69. // We correctly read the text/plain section of email
  70. content, err = ioutil.ReadAll(p)
  71. if err != nil {
  72. mailError.Printf("Error in ReadAll on part: %v", err)
  73. }
  74. break
  75. }
  76. } else {
  77. var err error
  78. content, err = ioutil.ReadAll(msg.Body)
  79. if err != nil {
  80. mailError.Printf("Couldn't read email body: %v", err)
  81. return
  82. }
  83. }
  84. mailInfo.Printf("Received mail from %s for %s with subject %s", from, to[0], subject)
  85. createPostFromEmail(to[0], subject, from, content)
  86. }
  87. func createPostFromEmail(to, subject, from string, content []byte) {
  88. if err := validate.Email(to); err != nil {
  89. return
  90. }
  91. }