A webmail client. Forked from https://git.sr.ht/~migadu/alps
25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 
 

139 satır
2.9 KiB

  1. package koushin
  2. import (
  3. "bufio"
  4. "fmt"
  5. "time"
  6. "io"
  7. "strings"
  8. "github.com/emersion/go-message/mail"
  9. "github.com/emersion/go-smtp"
  10. )
  11. func quote(r io.Reader) (string, error) {
  12. scanner := bufio.NewScanner(r)
  13. var builder strings.Builder
  14. for scanner.Scan() {
  15. builder.WriteString("> ")
  16. builder.Write(scanner.Bytes())
  17. builder.WriteString("\n")
  18. }
  19. if err := scanner.Err(); err != nil {
  20. return "", fmt.Errorf("quote: failed to read original message: %s", err)
  21. }
  22. return builder.String(), nil
  23. }
  24. func (s *Server) connectSMTP() (*smtp.Client, error) {
  25. var c *smtp.Client
  26. var err error
  27. if s.smtp.tls {
  28. c, err = smtp.DialTLS(s.smtp.host, nil)
  29. if err != nil {
  30. return nil, fmt.Errorf("failed to connect to SMTPS server: %v", err)
  31. }
  32. } else {
  33. c, err = smtp.Dial(s.smtp.host)
  34. if err != nil {
  35. return nil, fmt.Errorf("failed to connect to SMTP server: %v", err)
  36. }
  37. if !s.smtp.insecure {
  38. if err := c.StartTLS(nil); err != nil {
  39. c.Close()
  40. return nil, fmt.Errorf("STARTTLS failed: %v", err)
  41. }
  42. }
  43. }
  44. return c, err
  45. }
  46. type OutgoingMessage struct {
  47. From string
  48. To []string
  49. Subject string
  50. InReplyTo string
  51. Text string
  52. }
  53. func (msg *OutgoingMessage) ToString() string {
  54. return strings.Join(msg.To, ", ")
  55. }
  56. func (msg *OutgoingMessage) WriteTo(w io.Writer) error {
  57. from := []*mail.Address{{"", msg.From}}
  58. to := make([]*mail.Address, len(msg.To))
  59. for i, addr := range msg.To {
  60. to[i] = &mail.Address{"", addr}
  61. }
  62. var h mail.Header
  63. h.SetDate(time.Now())
  64. h.SetAddressList("From", from)
  65. h.SetAddressList("To", to)
  66. if msg.Subject != "" {
  67. h.SetText("Subject", msg.Subject)
  68. }
  69. if msg.InReplyTo != "" {
  70. h.Set("In-Reply-To", msg.InReplyTo)
  71. }
  72. mw, err := mail.CreateWriter(w, h)
  73. if err != nil {
  74. return fmt.Errorf("failed to create mail writer: %v", err)
  75. }
  76. var th mail.InlineHeader
  77. th.Set("Content-Type", "text/plain; charset=utf-8")
  78. tw, err := mw.CreateSingleInline(th)
  79. if err != nil {
  80. return fmt.Errorf("failed to create text part: %v", err)
  81. }
  82. defer tw.Close()
  83. if _, err := io.WriteString(tw, msg.Text); err != nil {
  84. return fmt.Errorf("failed to write text part: %v", err)
  85. }
  86. if err := tw.Close(); err != nil {
  87. return fmt.Errorf("failed to close text part: %v", err)
  88. }
  89. if err := mw.Close(); err != nil {
  90. return fmt.Errorf("failed to close mail writer: %v", err)
  91. }
  92. return nil
  93. }
  94. func sendMessage(c *smtp.Client, msg *OutgoingMessage) error {
  95. if err := c.Mail(msg.From, nil); err != nil {
  96. return fmt.Errorf("MAIL FROM failed: %v", err)
  97. }
  98. for _, to := range msg.To {
  99. if err := c.Rcpt(to); err != nil {
  100. return fmt.Errorf("RCPT TO failed: %v", err)
  101. }
  102. }
  103. w, err := c.Data()
  104. if err != nil {
  105. return fmt.Errorf("DATA failed: %v", err)
  106. }
  107. defer w.Close()
  108. if err := msg.WriteTo(w); err != nil {
  109. return fmt.Errorf("failed to write outgoing message: %v", err)
  110. }
  111. if err := w.Close(); err != nil {
  112. return fmt.Errorf("failed to close SMTP data writer: %v", err)
  113. }
  114. return nil
  115. }