func main() { from := flag.String("from", "", "From header for emails. Must be a bare email address.") subject := flag.String("subject", "", "Subject of emails") toFile := flag.String("toFile", "", "File containing a list of email addresses to send to, one per file.") bodyFile := flag.String("body", "", "File containing the email body in plain text format.") dryRun := flag.Bool("dryRun", true, "Whether to do a dry run.") sleep := flag.Duration("sleep", 60*time.Second, "How long to sleep between emails.") start := flag.Int("start", 0, "Line of input file to start from.") end := flag.Int("end", 99999999, "Line of input file to end before.") type config struct { NotifyMailer struct { cmd.DBConfig cmd.PasswordConfig cmd.SMTPConfig } } configFile := flag.String("config", "", "File containing a JSON config.") flag.Parse() if from == nil || subject == nil || bodyFile == nil || configFile == nil { flag.Usage() os.Exit(1) } _, log := cmd.StatsAndLogging(cmd.StatsdConfig{}, cmd.SyslogConfig{StdoutLevel: 7}) configData, err := ioutil.ReadFile(*configFile) cmd.FailOnError(err, fmt.Sprintf("Reading %s", *configFile)) var cfg config err = json.Unmarshal(configData, &cfg) cmd.FailOnError(err, "Unmarshaling config") dbURL, err := cfg.NotifyMailer.DBConfig.URL() cmd.FailOnError(err, "Couldn't load DB URL") dbMap, err := sa.NewDbMap(dbURL, 10) cmd.FailOnError(err, "Could not connect to database") // Load email body body, err := ioutil.ReadFile(*bodyFile) cmd.FailOnError(err, fmt.Sprintf("Reading %s", *bodyFile)) address, err := mail.ParseAddress(*from) cmd.FailOnError(err, fmt.Sprintf("Parsing %s", *from)) toBody, err := ioutil.ReadFile(*toFile) cmd.FailOnError(err, fmt.Sprintf("Reading %s", *toFile)) destinations := strings.Split(string(toBody), "\n") checkpointRange := interval{ start: *start, end: *end, } var mailClient bmail.Mailer if *dryRun { mailClient = bmail.NewDryRun(*address, log) } else { smtpPassword, err := cfg.NotifyMailer.PasswordConfig.Pass() cmd.FailOnError(err, "Failed to load SMTP password") mailClient = bmail.New( cfg.NotifyMailer.Server, cfg.NotifyMailer.Port, cfg.NotifyMailer.Username, smtpPassword, *address) } err = mailClient.Connect() cmd.FailOnError(err, fmt.Sprintf("Connecting to %s:%s", cfg.NotifyMailer.Server, cfg.NotifyMailer.Port)) defer func() { err = mailClient.Close() cmd.FailOnError(err, "Closing mail client") }() m := mailer{ clk: cmd.Clock(), log: log, dbMap: dbMap, mailer: mailClient, subject: *subject, destinations: destinations, emailTemplate: string(body), checkpoint: checkpointRange, sleepInterval: *sleep, } err = m.run() cmd.FailOnError(err, "mailer.send returned error") }
func main() { from := flag.String("from", "", "From header for emails. Must be a bare email address.") subject := flag.String("subject", "", "Subject of emails") toFile := flag.String("toFile", "", "File containing a JSON array of registration IDs to send to.") bodyFile := flag.String("body", "", "File containing the email body in plain text format.") dryRun := flag.Bool("dryRun", true, "Whether to do a dry run.") sleep := flag.Duration("sleep", 60*time.Second, "How long to sleep between emails.") start := flag.Int("start", 0, "Line of input file to start from.") end := flag.Int("end", 99999999, "Line of input file to end before.") reconnBase := flag.Duration("reconnectBase", 1*time.Second, "Base sleep duration between reconnect attempts") reconnMax := flag.Duration("reconnectMax", 5*60*time.Second, "Max sleep duration between reconnect attempts after exponential backoff") type config struct { NotifyMailer struct { cmd.DBConfig cmd.PasswordConfig cmd.SMTPConfig } Statsd cmd.StatsdConfig Syslog cmd.SyslogConfig } configFile := flag.String("config", "", "File containing a JSON config.") flag.Usage = func() { fmt.Fprintf(os.Stderr, "%s\n\n", usageIntro) fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0]) flag.PrintDefaults() } flag.Parse() if *from == "" || *subject == "" || *bodyFile == "" || *configFile == "" { flag.Usage() os.Exit(1) } configData, err := ioutil.ReadFile(*configFile) cmd.FailOnError(err, fmt.Sprintf("Reading %q", *configFile)) var cfg config err = json.Unmarshal(configData, &cfg) cmd.FailOnError(err, "Unmarshaling config") stats, log := cmd.StatsAndLogging(cfg.Statsd, cfg.Syslog) scope := metrics.NewStatsdScope(stats, "NotificationMailer") defer log.AuditPanic() dbURL, err := cfg.NotifyMailer.DBConfig.URL() cmd.FailOnError(err, "Couldn't load DB URL") dbMap, err := sa.NewDbMap(dbURL, 10) cmd.FailOnError(err, "Could not connect to database") go sa.ReportDbConnCount(dbMap, scope) // Load email body body, err := ioutil.ReadFile(*bodyFile) cmd.FailOnError(err, fmt.Sprintf("Reading %q", *bodyFile)) address, err := mail.ParseAddress(*from) cmd.FailOnError(err, fmt.Sprintf("Parsing %q", *from)) toBody, err := ioutil.ReadFile(*toFile) cmd.FailOnError(err, fmt.Sprintf("Reading %q", *toFile)) checkpointRange := interval{ start: *start, end: *end, } var mailClient bmail.Mailer if *dryRun { mailClient = bmail.NewDryRun(*address, log) } else { smtpPassword, err := cfg.NotifyMailer.PasswordConfig.Pass() cmd.FailOnError(err, "Failed to load SMTP password") mailClient = bmail.New( cfg.NotifyMailer.Server, cfg.NotifyMailer.Port, cfg.NotifyMailer.Username, smtpPassword, *address, log, scope, *reconnBase, *reconnMax) } m := mailer{ clk: cmd.Clock(), log: log, dbMap: dbMap, mailer: mailClient, subject: *subject, destinations: toBody, emailTemplate: string(body), checkpoint: checkpointRange, sleepInterval: *sleep, } err = m.run() cmd.FailOnError(err, "mailer.send returned error") }