sender.go

 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	// Format the From header to include the sender's name.
45	fromHeader := cfg.Email
46	if cfg.Name != "" {
47		fromHeader = fmt.Sprintf("%s <%s>", cfg.Name, cfg.Email)
48	}
49
50	// Construct the full email message with proper headers.
51	headers := map[string]string{
52		"From":         fromHeader,
53		"To":           to[0], // Assuming one recipient for the header display
54		"Subject":      subject,
55		"Date":         time.Now().Format(time.RFC1123Z),
56		"Message-ID":   generateMessageID(cfg.Email),
57		"Content-Type": "text/plain; charset=UTF-8", // Explicitly set content type
58	}
59
60	var msg string
61	for k, v := range headers {
62		msg += fmt.Sprintf("%s: %s\r\n", k, v)
63	}
64	msg += "\r\n" + body
65
66	// SMTP server address.
67	addr := fmt.Sprintf("%s:%d", smtpServer, smtpPort)
68
69	// Send the email.
70	err := smtp.SendMail(addr, auth, cfg.Email, to, []byte(msg))
71	return err
72}