1package sender
2
3import (
4 "crypto/rand"
5 "fmt"
6 "net/smtp"
7 "time"
8
9 "github.com/andrinoff/email-cli/config"
10)
11
12// generateMessageID creates a unique Message-ID header.
13// This is a crucial header for deliverability, as its absence is a spam indicator.
14func generateMessageID(from string) string {
15 // Generate a random part to ensure uniqueness
16 buf := make([]byte, 16)
17 _, err := rand.Read(buf)
18 if err != nil {
19 // Fallback to a less random but still unique value if crypto/rand fails
20 return fmt.Sprintf("<%d.%s>", time.Now().UnixNano(), from)
21 }
22 return fmt.Sprintf("<%x@%s>", buf, from)
23}
24
25func SendEmail(cfg *config.Config, to []string, subject, body string) error {
26 var smtpServer string
27 var smtpPort int
28
29 // Determine the SMTP server based on the service provider in the config.
30 switch cfg.ServiceProvider {
31 case "gmail":
32 smtpServer = "smtp.gmail.com"
33 smtpPort = 587
34 case "icloud":
35 smtpServer = "smtp.mail.me.com"
36 smtpPort = 587
37 default:
38 return fmt.Errorf("unsupported or missing service_provider in config.json: %s", cfg.ServiceProvider)
39 }
40
41 // Set up authentication information.
42 auth := smtp.PlainAuth("", cfg.Email, cfg.Password, smtpServer)
43
44 // Construct the full email message with proper headers.
45 headers := map[string]string{
46 "From": cfg.Email,
47 "To": to[0], // Assuming one recipient for the header display
48 "Subject": subject,
49 "Message-ID": generateMessageID(cfg.Email),
50 "Content-Type": "text/plain; charset=UTF-8", // Explicitly set content type
51 }
52
53 var msg string
54 for k, v := range headers {
55 msg += fmt.Sprintf("%s: %s\r\n", k, v)
56 }
57 msg += "\r\n" + body
58
59 // SMTP server address.
60 addr := fmt.Sprintf("%s:%d", smtpServer, smtpPort)
61
62 // Send the email.
63 err := smtp.SendMail(addr, auth, cfg.Email, to, []byte(msg))
64 return err
65}