Commit 0a997c5
Eric Bower
·
2025-08-30 08:22:02 -0400 EDT
parent d80b355
chore(feeds): better formatting for smtp emails
1 files changed,
+23,
-11
+23,
-11
| ... | ... | @@ -132,11 +132,14 @@ type Fetcher struct { | |
| 132 | 132 | db db.DB | |
| 133 | 133 | auth sasl.Client | |
| 134 | 134 | gron *gronx.Gronx | |
| 135 | + | host string | |
| 135 | 136 | } | |
| 136 | 137 | ||
| 137 | 138 | func NewFetcher(dbpool db.DB, cfg *shared.ConfigSite) *Fetcher { | |
| 139 | + | host := os.Getenv("PICO_SMTP_HOST") | |
| 138 | 140 | smtPass := os.Getenv("PICO_SMTP_PASS") | |
| 139 | 141 | emailLogin := os.Getenv("PICO_SMTP_USER") | |
| 142 | + | ||
| 140 | 143 | auth := sasl.NewPlainClient("", emailLogin, smtPass) | |
| 141 | 144 | gron := gronx.New() | |
| 142 | 145 | return &Fetcher{ |
| ... | ... | @@ -144,6 +147,7 @@ func NewFetcher(dbpool db.DB, cfg *shared.ConfigSite) *Fetcher { | |
| 144 | 147 | cfg: cfg, | |
| 145 | 148 | auth: auth, | |
| 146 | 149 | gron: gron, | |
| 150 | + | host: host, | |
| 147 | 151 | } | |
| 148 | 152 | } | |
| 149 | 153 |
| ... | ... | @@ -253,7 +257,8 @@ func (f *Fetcher) RunPost(logger *slog.Logger, user *db.User, post *db.Post, ski | |
| 253 | 257 | return err | |
| 254 | 258 | } | |
| 255 | 259 | ||
| 256 | - | subject := fmt.Sprintf("%s feed digest", post.Title) | |
| 260 | + | subject := fmt.Sprintf("%s feed digest", post.Filename) | |
| 261 | + | unsubURL := getUnsubURL(post) | |
| 257 | 262 | ||
| 258 | 263 | msgBody, err := f.FetchAll(logger, urls, parsed.InlineContent, user.Name, post) | |
| 259 | 264 | if err != nil { |
| ... | ... | @@ -277,9 +282,11 @@ Also, we have centralized logs in our pico.sh TUI that will display realtime fee | |
| 277 | 282 | ||
| 278 | 283 | %s`, post.Data.Attempts, maxAttempts, errForUser.Error(), post.Text) | |
| 279 | 284 | err = f.SendEmail( | |
| 280 | - | logger, user.Name, | |
| 285 | + | logger, | |
| 286 | + | user.Name, | |
| 281 | 287 | parsed.Email, | |
| 282 | 288 | subject, | |
| 289 | + | unsubURL, | |
| 283 | 290 | &MsgBody{Html: strings.ReplaceAll(errBody, "\n", "<br />"), Text: errBody}, | |
| 284 | 291 | ) | |
| 285 | 292 | if err != nil { |
| ... | ... | @@ -307,7 +314,7 @@ Also, we have centralized logs in our pico.sh TUI that will display realtime fee | |
| 307 | 314 | } | |
| 308 | 315 | ||
| 309 | 316 | if msgBody != nil { | |
| 310 | - | err = f.SendEmail(logger, user.Name, parsed.Email, subject, msgBody) | |
| 317 | + | err = f.SendEmail(logger, user.Name, parsed.Email, subject, unsubURL, msgBody) | |
| 311 | 318 | if err != nil { | |
| 312 | 319 | return err | |
| 313 | 320 | } |
| ... | ... | @@ -460,6 +467,10 @@ type MsgBody struct { | |
| 460 | 467 | Text string | |
| 461 | 468 | } | |
| 462 | 469 | ||
| 470 | + | func getUnsubURL(post *db.Post) string { | |
| 471 | + | return fmt.Sprintf("https://feeds.pico.sh/unsub/%s", post.ID) | |
| 472 | + | } | |
| 473 | + | ||
| 463 | 474 | func (f *Fetcher) FetchAll(logger *slog.Logger, urls []string, inlineContent bool, username string, post *db.Post) (*MsgBody, error) { | |
| 464 | 475 | logger.Info("fetching feeds", "inlineContent", inlineContent) | |
| 465 | 476 | fp := gofeed.NewParser() |
| ... | ... | @@ -475,7 +486,7 @@ func (f *Fetcher) FetchAll(logger *slog.Logger, urls []string, inlineContent boo | |
| 475 | 486 | } | |
| 476 | 487 | feeds := &DigestFeed{ | |
| 477 | 488 | KeepAliveURL: fmt.Sprintf("https://feeds.pico.sh/keep-alive/%s", post.ID), | |
| 478 | - | UnsubURL: fmt.Sprintf("https://feeds.pico.sh/unsub/%s", post.ID), | |
| 489 | + | UnsubURL: getUnsubURL(post), | |
| 479 | 490 | DaysLeft: daysLeft, | |
| 480 | 491 | ShowBanner: showBanner, | |
| 481 | 492 | Options: DigestOptions{InlineContent: inlineContent}, |
| ... | ... | @@ -564,19 +575,20 @@ func (f *Fetcher) FetchAll(logger *slog.Logger, urls []string, inlineContent boo | |
| 564 | 575 | }, nil | |
| 565 | 576 | } | |
| 566 | 577 | ||
| 567 | - | func (f *Fetcher) SendEmail(logger *slog.Logger, username, email, subject string, msg *MsgBody) error { | |
| 578 | + | func (f *Fetcher) SendEmail(logger *slog.Logger, username, email, subject, unsubURL string, msg *MsgBody) error { | |
| 568 | 579 | if email == "" { | |
| 569 | 580 | return fmt.Errorf("(%s) does not have an email associated with their feed post", username) | |
| 570 | 581 | } | |
| 571 | - | smtpAddr := "smtp.fastmail.com:587" | |
| 582 | + | smtpAddr := f.host | |
| 572 | 583 | fromEmail := "hello@pico.sh" | |
| 573 | 584 | to := []string{email} | |
| 574 | 585 | headers := map[string]string{ | |
| 575 | - | "From": fromEmail, | |
| 576 | - | "To": email, | |
| 577 | - | "Subject": subject, | |
| 578 | - | "MIME-Version": "1.0", | |
| 579 | - | "Content-Type": `multipart/alternative; boundary="boundary123"`, | |
| 586 | + | "From": fromEmail, | |
| 587 | + | "Subject": subject, | |
| 588 | + | "To": email, | |
| 589 | + | "MIME-Version": "1.0", | |
| 590 | + | "Content-Type": `multipart/alternative; boundary="boundary123"`, | |
| 591 | + | "List-Unsubscribe": "<" + unsubURL + ">", | |
| 580 | 592 | } | |
| 581 | 593 | var content strings.Builder | |
| 582 | 594 | for k, v := range headers { |