12 func MarshalMail(activity *Activity) ([]byte, error) {
13 buf := &bytes.Buffer{}
15 actor, err := LookupActor(activity.AttributedTo)
17 return nil, fmt.Errorf("lookup actor %s: %w", activity.AttributedTo, err)
19 fmt.Fprintf(buf, "From: %s\n", actor.Address())
21 if activity.CC != nil {
22 buf.WriteString("To: ")
23 rcpt := append(activity.To, activity.CC...)
25 for _, u := range rcpt {
29 actor, err = LookupActor(u)
31 return nil, fmt.Errorf("lookup actor %s: %w", u, err)
33 addrs = append(addrs, actor.Address().String())
35 buf.WriteString(strings.Join(addrs, ", "))
39 fmt.Fprintf(buf, "Date: %s\n", activity.Published.Format(time.RFC822))
40 fmt.Fprintf(buf, "Message-ID: <%s>\n", activity.ID)
41 if activity.Audience != "" {
42 fmt.Fprintf(buf, "List-ID: <%s>\n", activity.Audience)
44 if activity.InReplyTo != "" {
45 fmt.Fprintf(buf, "References: <%s>\n", activity.InReplyTo)
48 if activity.Source.Content != "" && activity.Source.MediaType == "text/markdown" {
49 fmt.Fprintln(buf, "Content-Type: text/plain; charset=utf-8")
51 fmt.Fprintln(buf, "Content-Type:", activity.MediaType)
53 fmt.Fprintln(buf, "Subject:", activity.Name)
55 if activity.Source.Content != "" && activity.Source.MediaType == "text/markdown" {
56 fmt.Fprintln(buf, activity.Source.Content)
58 fmt.Fprintln(buf, activity.Content)
60 _, err = mail.ReadMessage(bytes.NewReader(buf.Bytes()))
61 return buf.Bytes(), err
64 func SendMail(client *smtp.Client, activity *Activity, from string, to ...string) error {
65 b, err := MarshalMail(activity)
67 return fmt.Errorf("marshal to mail message: %w", err)
69 if err := client.Mail(from); err != nil {
70 return fmt.Errorf("mail command: %w", err)
72 for _, rcpt := range to {
73 if err := client.Rcpt(rcpt); err != nil {
74 return fmt.Errorf("rcpt command: %w", err)
77 wc, err := client.Data()
79 return fmt.Errorf("data command: %w", err)
81 if _, err := wc.Write(b); err != nil {
82 return fmt.Errorf("write message: %w", err)
84 if err := wc.Close(); err != nil {
85 return fmt.Errorf("close message writer: %w", err)