go-mail
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

批量邮件示例

在这个示例中,我们创建了一个小型的批量邮件发送程序,可以将相同的邮件发送给更多的收件人。 In this example we create a small bulk mailer for sending out the same mail to a bigger list of recipients. It is important for us to address the recipient directly in the mail, therefore we will make use of Go’s html/template and text/template system together with placeholders.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
package main

import (
    "fmt"
    ht "html/template"
    "log"
    "math/rand"
    "os"
    tt "text/template"
    "time"

    "github.com/wneessen/go-mail"
)

// User is a simple type allowing us to set a firstname, lastname and mail address
type User struct {
    Firstname string
    Lastname  string
    EmailAddr string
}

// Our sender information that will be used in the FROM address field
const (
    senderName = "ACME Inc."
    senderAddr = "noreply@acme.com"
)

const (
    textBodyTemplate = `Hi {{.Firstname}},

we are writing your to let you know that this week we have an amazing offer for you.
Using the coupon code "GOMAIL" you will get a 20% discount on all our products in our
online shop.

Check out our latest offer on https://acme.com and use your discount code today!

Your marketing team
  at ACME Inc.`

    htmlBodyTemplate = `<p>Hi {{.Firstname}},</p>
<p>we are writing your to let you know that this week we have an amazing offer for you.
package main

import (
    "fmt"
    ht "html/template"
    "log"
    "math/rand"
    "os"
    tt "text/template"
    "time"

    "github.com/wneessen/go-mail"
)

// User is a simple type allowing us to set a firstname, lastname and mail address
type User struct {
    Firstname string
    Lastname  string
    EmailAddr string
}

// Our sender information that will be used in the FROM address field
const (
    senderName = "ACME Inc."
    senderAddr = "noreply@acme.com"
)

const (
    textBodyTemplate = `Hi {{.Firstname}},

we are writing your to let you know that this week we have an amazing offer for you.
Using the coupon code "GOMAIL" you will get a 20% discount on all our products in our
online shop.

Check out our latest offer on https://acme.com and use your discount code today!

Your marketing team
  at ACME Inc.`

    htmlBodyTemplate = `<p>Hi {{.Firstname}},</p>
<p>we are writing your to let you know that this week we have an amazing offer for you.
package main

import (
    "fmt"
    ht "html/template"
    "log"
    "math/rand"
    "os"
    tt "text/template"
    "time"

    "github.com/wneessen/go-mail"
)

// User is a simple type allowing us to set a firstname, lastname and mail address
type User struct {
    Firstname string
    Lastname  string
    EmailAddr string
}

// Our sender information that will be used in the FROM address field
const (
    senderName = "ACME Inc."
    senderAddr = "noreply@acme.com"
)

const (
    textBodyTemplate = `Hi {{.Firstname}},

we are writing your to let you know that this week we have an amazing offer for you.
Using the coupon code "GOMAIL" you will get a 20% discount on all our products in our
online shop.

Check out our latest offer on https://acme.com and use your discount code today!

Your marketing team
  at ACME Inc.`

    htmlBodyTemplate = `<p>Hi {{.Firstname}},</p>
<p>we are writing your to let you know that this week we have an amazing offer for you.
package main

import (
    "fmt"
    ht "html/template"
    "log"
    "math/rand"
    "os"
    tt "text/template"
    "time"

    "github.com/wneessen/go-mail"
)

// User is a simple type allowing us to set a firstname, lastname and mail address
type User struct {
    Firstname string
    Lastname  string
    EmailAddr string
}

// Our sender information that will be used in the FROM address field
const (
    senderName = "ACME Inc."
    senderAddr = "noreply@acme.com"
)

const (
    textBodyTemplate = `Hi {{.Firstname}},

we are writing your to let you know that this week we have an amazing offer for you.
Using the coupon code "GOMAIL" you will get a 20% discount on all our products in our
online shop.

Check out our latest offer on https://acme.com and use your discount code today!

Your marketing team
  at ACME Inc.`

    htmlBodyTemplate = `<p>Hi {{.Firstname}},</p>
<p>we are writing your to let you know that this week we have an amazing offer for you.
Using the coupon code "<strong>GOMAIL</strong>" you will get a 20% discount on all 
our products in our online shop.</p>
<p>Check out our latest offer on <a href="https://acme.com" target="_blank">https://acme.com</a>
and use your discount code today!</p>
<p>Your marketing team<br />
&nbsp;&nbsp;at ACME Inc.</p>`
)

func main() {
    // Define a list of users we want to mail to
    ul := []User{
        {"Toni", "Tester", "toni.tester@example.com"},
        {"Tina", "Tester", "tina.tester@example.com"},
        {"John", "Doe", "john.doe@example.com"},
    }

    // Prepare the different templates
    ttpl, err := tt.New("texttpl").Parse(textBodyTemplate)
    if err != nil {
        log.Fatalf("failed to parse text template: %s", err)
    }
    htpl, err := ht.New("htmltpl").Parse(htmlBodyTemplate)
    if err != nil {
        log.Fatalf("failed to parse text template: %s", err)
    }

    var ms []*mail.Msg
    r := rand.New(rand.NewSource(time.Now().UnixNano()))
    for _, u := range ul {
        rn := r.Int31()
        m := mail.NewMsg()
        if err := m.EnvelopeFrom(fmt.Sprintf("noreply+%d@acme.com", rn)); err != nil {
            log.Fatalf("failed to set ENVELOPE FROM address: %s", err)
        }
        if err := m.FromFormat(senderName, senderAddr); err != nil {
            log.Fatalf("failed to set formatted FROM address: %s", err)
        }
        if err := m.AddToFormat(fmt.Sprintf("%s %s", u.Firstname, u.Lastname), u.EmailAddr); err != nil {
            log.Fatalf("failed to set formatted TO address: %s", err)
        }
        m.SetMessageID()
        m.SetDate()
        m.SetBulk()
        m.Subject(fmt.Sprintf("%s, we have a great offer for you!", u.Firstname))
        if err := m.SetBodyHTMLTemplate(htpl, u); err != nil {
            log.Fatalf("failed to set HTML template as HTML body: %s", err)
        }
        if err := m.AddAlternativeTextTemplate(ttpl, u); err != nil {
            log.Fatalf("failed to set text template as alternative body: %s", err)
        }

        ms = append(ms, m)
    }

    // Deliver the mails via SMTP
    c, err := mail.NewClient("smtp.example.com",
        mail.WithSMTPAuth(mail.SMTPAuthPlain), mail.WithTLSPortPolicy(mail.TLSMandatory),
        mail.WithUsername(os.Getenv("SMTP_USER")), mail.WithPassword(os.Getenv("SMTP_PASS")),
    )
    if err := c.DialAndSend(ms...); err != nil {
        log.Fatalf("failed to deliver mail: %s", err)
    }
    log.Printf("Bulk mailing successfully delivered.")
}
}
}
}

Let’s take the example apart to look at some details…

At first, in line 15, we define a new type for our users that we want to address. This is totally optional and is only done so we can easily work with a list of users and address them later on in our text template. How you handle this, is totally up to you and not mandatory for this to work. This is totally optional and is only done so we can easily work with a list of users and address them later on in our text template. How you handle this, is totally up to you and not mandatory for this to work.

In line 28 thru 48 we set up a simple text and HTML template mail body with placeholders that can be used with Go’s html/template and text/template.

Next we set up a list of users, we want to send our great bulk mailing to. Line 52 uses the User type for this. With the preparation work done, we will start looping over all of our users in line 70. For each user we create a new *mail.Msg. Line 52 uses the User type for this. With the preparation work done, we will start looping over all of our users in line 70. For each user we create a new *mail.Msg.

For bulk mailings it is common that the ENVELOPE FROM and the MAIL FROM differ, so that bounce mails are sent to some system that can mark those bounces in the local system as bounced. Therefore we set both of those from addresses in line 73 and line 76. The lines 79 to 85 should be of no surprise to you, if you already used go-mail before. Therefore we set both of those from addresses in line 73 and line 76. The lines 79 to 85 should be of no surprise to you, if you already used go-mail before.

One more interesting thing happens in lines 86 thru 91 in which we use our prepared html/template and text/template templates and apply it to our mail message using m.SetBodyHTMLTemplate and m.AddAlternativeTextTemplate. We provide the whole user struct as data to that methods, so that html/template and text/template can take care of replacing placeholders in the mail body. Go-mail will take care of all the bells and whistles with the template handling for you. With our mail message now complete, we append it to our mail message slice in line 93. We provide the whole user struct as data to that methods, so that html/template and text/template can take care of replacing placeholders in the mail body. Go-mail will take care of all the bells and whistles with the template handling for you. With our mail message now complete, we append it to our mail message slice in line 93. We provide the whole user struct as data to that methods, so that html/template and text/template can take care of replacing placeholders in the mail body. Go-mail will take care of all the bells and whistles with the template handling for you. With our mail message now complete, we append it to our mail message slice in line 93. We provide the whole user struct as data to that methods, so that html/template and text/template can take care of replacing placeholders in the mail body. Go-mail will take care of all the bells and whistles with the template handling for you. With our mail message now complete, we append it to our mail message slice in line 93.

Finally we create a new Client and send out all of our prepared messages in one go by providing the whole slice of messages to Client.DialAndSend.