Giter VIP home page Giter VIP logo

go-mail's Introduction

Go Mail Logo

made-with-Go Go Report Card Test codecov go.dev reference Twitter Handle

๐Ÿ“ง Go Mail

A cross-platform mail driver for GoLang. Featuring Mailgun, Postal, Postmark, SendGrid, SparkPost & SMTP.

Overview

  • โœ… Multiple mail drivers for your needs or even create your own custom Mailer.
  • โœ… Direct dependency free, all requests are made with the standard lib http.Client.
  • โœ… Send attachments with two struct fields, it's extremely simple.
  • โœ… Send CC & BCC messages.
  • โœ… Extremely lightweight.

Supported API's

Introduction

Go Mail aims to unify multiple popular mail APIs into a singular, easy to use interface. Email sending is seriously simple and great for allowing the developer or end user to choose what platform they use.

cfg := mail.Config{
    URL:         "https://api.eu.sparkpost.com",
    APIKey:      "my-key",
    FromAddress: "[email protected]",
    FromName:    "Gopher",
}

mailer, err := drivers.NewSparkPost(cfg)
if err != nil {
	log.Fatalln(err)
}

tx := &mail.Transmission{
    Recipients:  []string{"[email protected]"},
    Subject:     "My email",
    HTML:        "<h1>Hello from Go Mail!</h1>",
}

result, err := mailer.Send(tx)
if err != nil {
	log.Fatalln(err)
}

fmt.Printf("%+v\n", result)

Installation

go get -u github.com/ainsleyclark/go-mail

Docs

Documentation can be found at the Go Docs, but we have included a kick-start guide below to get you started.

Creating a new client:

You can create a new driver by calling the drivers package and passing in a configuration type which is required to create a new mailer. Each platform requires its own data, for example, Mailgun requires a domain, but SparkPost doesn't. This is based of the requirements for the API. For more details see the examples below.

cfg := mail.Config{
	URL:         "https://api.eu.sparkpost.com",
	APIKey:      "my-key",
	FromAddress: "[email protected]",
	FromName:    "Gopher",
	Client:       http.DefaultClient, // Client is optional
}

mailer, err := drivers.NewSparkpost(cfg)
if err != nil {
	log.Fatalln(err)
}

Sending Data:

A transmission is required to transmit to a mailer as shown below. Once send is called, a mail.Response and an error be returned indicating if the transmission was successful.

tx := &mail.Transmission{
	Recipients: []string{"[email protected]"},
	CC:         []string{"[email protected]"},
	BCC:        []string{"[email protected]"},
	Subject:    "My email",
	HTML:       "<h1>Hello from Go Mail!</h1>",
	PlainText:  "Hello from Go Mail!",
	Headers: map[string]string{
		"X-Go-Mail": "Test",
	},
}

result, err := mailer.Send(tx)
if err != nil {
	log.Fatalln(err)
}

fmt.Printf("%+v\n", result)

Response:

The mail response is used for debugging and inspecting results of the mailer. Below is the Response type.

// Response represents the data passed back from a successful transmission.
type Response struct {
	StatusCode int         // e.g. 200
	Body       []byte      // e.g. {"result: success"}
	Headers    http.Header // e.g. map[X-Ratelimit-Limit:[600]]
	ID         string      // e.g "100"
	Message    string      // e.g "Email sent successfully"
}

Adding attachments:

Adding attachments to the transmission is as simple as passing a byte slice and filename. Go Mail takes care of the rest for you.

image, err := ioutil.ReadFile("gopher.jpg")
if err != nil {
	log.Fatalln(err)
}

tx := &mail.Transmission{
	Recipients: []string{"[email protected]"},
	Subject:    "My email",
	HTML:       "<h1>Hello from Go Mail!</h1>",
	PlainText:  "plain text",
	Attachments: []mail.Attachment{
		{
			Filename: "gopher.jpg",
			Bytes:    image,
		},
	},
}

Examples

Mailgun

cfg := mail.Config{
URL:         "https://api.eu.mailgun.net", // Or https://api.mailgun.net
	APIKey:      "my-key",
	FromAddress: "[email protected]",
	FromName:    "Gopher",
	Domain:      "my-domain.com",
}

mailer, err := drivers.NewMailgun(cfg)
if err != nil {
	log.Fatalln(err)
}

tx := &mail.Transmission{
	Recipients: []string{"[email protected]"},
	CC:         []string{"[email protected]"},
	BCC:        []string{"[email protected]"},
	Subject:    "My email",
	HTML:       "<h1>Hello from Go Mail!</h1>",
	PlainText:  "Hello from Go Mail!",
}

result, err := mailer.Send(tx)
if err != nil {
	log.Fatalln(err)
}

fmt.Printf("%+v\n", result)

Postal

cfg := mail.Config{
	URL:         "https://postal.example.com",
	APIKey:      "my-key",
	FromAddress: "[email protected]",
	FromName:    "Gopher",
}

mailer, err := drivers.NewPostal(cfg)
if err != nil {
	log.Fatalln(err)
}

tx := &mail.Transmission{
	Recipients: []string{"[email protected]"},
	CC:         []string{"[email protected]"},
	BCC:        []string{"[email protected]"},
	Subject:    "My email",
	HTML:       "<h1>Hello from Go Mail!</h1>",
	PlainText:  "Hello from Go Mail!",
}

result, err := mailer.Send(tx)
if err != nil {
	log.Fatalln(err)
}

fmt.Printf("%+v\n", result)

Postmark

cfg := mail.Config{
	APIKey:      "my-key",
	FromAddress: "[email protected]",
	FromName:    "Gopher",
}

mailer, err := drivers.NewPostmark(cfg)
if err != nil {
	log.Fatalln(err)
}

tx := &mail.Transmission{
	Recipients: []string{"[email protected]"},
	CC:         []string{"[email protected]"},
	BCC:        []string{"[email protected]"},
	Subject:    "My email",
	HTML:       "<h1>Hello from Go Mail!</h1>",
	PlainText:  "Hello from Go Mail!",
}

result, err := mailer.Send(tx)
if err != nil {
	log.Fatalln(err)
}

fmt.Printf("%+v\n", result)

SendGrid

cfg := mail.Config{
	APIKey:      "my-key",
	FromAddress: "[email protected]",
	FromName:    "Gopher",
}

mailer, err := drivers.NewSendGrid(cfg)
if err != nil {
	log.Fatalln(err)
}

tx := &mail.Transmission{
	Recipients: []string{"[email protected]"},
	CC:         []string{"[email protected]"},
	BCC:        []string{"[email protected]"},
	Subject:    "My email",
	HTML:       "<h1>Hello from Go Mail!</h1>",
	PlainText:  "Hello from Go Mail!",
}

result, err := mailer.Send(tx)
if err != nil {
	log.Fatalln(err)
}

fmt.Printf("%+v\n", result)

SMTP

cfg := mail.Config{
	URL:         "smtp.gmail.com",
	FromAddress: "[email protected]",
	FromName:    "Gopher",
	Password:    "my-password",
	Port:        587,
}

mailer, err := drivers.NewSMTP(cfg)
if err != nil {
	log.Fatalln(err)
}

tx := &mail.Transmission{
	Recipients: []string{"[email protected]"},
	CC:         []string{"[email protected]"},
	BCC:        []string{"[email protected]"},
	Subject:    "My email",
	HTML:       "<h1>Hello from Go Mail!</h1>",
	PlainText:  "Hello from Go Mail!",
}

result, err := mailer.Send(tx)
if err != nil {
	log.Fatalln(err)
}

fmt.Printf("%+v\n", result)

SparkPost

cfg := mail.Config{
	URL:         "https://api.eu.sparkpost.com", // Or https://api.sparkpost.com/api/v1
	APIKey:      "my-key",
	FromAddress: "[email protected]",
	FromName:    "Gopher",
}

mailer, err := drivers.NewSparkPost(cfg)
if err != nil {
	log.Fatalln(err)
}

tx := &mail.Transmission{
	Recipients: []string{"[email protected]"},
	CC:         []string{"[email protected]"},
	BCC:        []string{"[email protected]"},
	Subject:    "My email",
	HTML:       "<h1>Hello from Go Mail!</h1>",
	PlainText:  "Hello from Go Mail!",
}

result, err := mailer.Send(tx)
if err != nil {
	log.Fatalln(err)
}

fmt.Printf("%+v\n", result)

Writing a Mailable

You have the ability to create your own custom Mailer by implementing the singular method interface shown below.

type Mailer interface {
	// Send accepts a mail.Transmission to send an email through a particular
	// driver/provider. Transmissions will be validated before sending.
	//
	// A mail.Response or an error will be returned. In some circumstances
	// the body and status code will be attached to the response for debugging.
	Send(t *mail.Transmission) (mail.Response, error)
}

Debugging

To debug any errors or issues you are facing with Go Mail, you are able to change the Debug variable in the mail package. This will write the HTTP requests in curl to stdout. Additional information will also be displayed in the errors such as method operations.

mail.Debug = true

Development

Setup

To get set up with Go Mail simply clone the repo and run the following:

go get github.com/vektra/mockery/v2/.../
make setup
make mocks

Env

All secrets are contained within the .env file for testing drivers. To begin with, make a copy of the .env.example file and name it .env. You can the set the environment variables to match your credentials for the mail drivers.

You can set the recipients of emails by modifying the EMAIL variables as show below.

  • EMAIL_TO: Recipients of test emails in a comma delimited list.
  • EMAIL_CC: CC recipients of test emails in a comma delimited list.
  • EMAIL_BCC: BCC recipients of test emails in a comma delimited list.

Testing

To run all driver tests, execute the following command:

make test-driver

To run a specific driver test, prepend the driver flag as show below:

make test-driver driver=sparkpost

The driver flag can be one of the following:

  • mailgun
  • postal
  • postmark
  • sendgrid
  • smtp
  • sparkpost

Contributing

We welcome contributors, but please read the contributing document before making a pull request.

Credits

Shout out to the incredible Maria Letta for her excellent Gopher illustrations.

Licence

Code Copyright 2022 Go Mail. Code released under the MIT Licence.

go-mail's People

Contributors

ainsleyclark avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

go-mail's Issues

Changes in v1.1.x break any project that imports v1.0.x

Hi:

I don't suppose that you could move v1.1.x to a v2 branch; any project that uses this package and wrote code as required in v1.0.x now breaks when go get -u is executed, since you've moved to the (much better) approach that you have in version 1.1.x.

Obviously, this is not a huge deal, but it would make life easier for those of us who are using your package, and it also is a more correct approach of versioning, since v1.1.x introduces breaking changes.

This is just a suggestion, of course.

Thanks again for this useful package.

Remove External Deps

Remove external go.mod dependencies for the following.
Ensure only native http.Client is used for the sending of mail.

  • github.com/SparkPost/gosparkpost
  • github.com/sendgrid/sendgrid-go
  • github.com/sendgrid/rest
  • github.com/mailgun/mailgun-go/v4

Mailgun

Great package!

The only problem I am running into, and I'm sure it's me, is that when I try to send through mailgun, my HTML message gets rendered in the mail client with the wrong content type (text/plain).

Below is the code used to send, and below is the sample email (raw) received.

That is, the message displayed in the browser appears to have the correct payload, but the user gets to read raw html rather than a nicely formatted message.

Any idea what I'm doing wrong?

cfg := mail.Config{
    URL:         "https://api.mailgun.net/",
    APIKey:      "someapikey",
    FromAddress: mailMessage.FromAddress,
    FromName:    mailMessage.FromName,
    Domain:      "mg.mydomain.com",
}

driver, err := mail.NewClient(mail.MailGun, cfg)
    if err != nil {
    fmt.Println(err)
}

var toSlice []string
toSlice = append(toSlice, mailMessage.ToAddress)

formattedMessage = "<h1>Hello, world</h1>"
plainText := "Hello, world"

tx := &mail.Transmission{
    Recipients: toSlice,
    Subject:    mailMessage.Subject,
    HTML:       formattedMessage,
    PlainText: plainText,
}

rs, err := driver.Send(tx)
    if err != nil {
    fmt.Println(err)
}

fmt.Println(rs)

And here is the resulting message:

Delivered-To: [email protected]
Received: by 2002:a05:6602:2816:0:0:0:0 with SMTP id d22csp709301ioe;
Sun, 11 Apr 2021 06:46:55 -0700 (PDT)
X-Google-Smtp-Source: ABdhPJyYhhmrpu7UvmoOFLE1Vl0fb2bUd4fYYpfMjrIacwmORyXF9WkHqNdSgejUFlyJNHcr/vT2
X-Received: by 2002:a05:6820:451:: with SMTP id p17mr19136528oou.93.1618148815224;
Sun, 11 Apr 2021 06:46:55 -0700 (PDT)
ARC-Seal: i=1; a=rsa-sha256; t=1618148815; cv=none;
d=google.com; s=arc-20160816;
b=g2Sc5tbiMNl9Lk6GDXfByhcD4pjTiA1zIArM+FhOttmsqvMirqnoE3ZO1K/Q5nHWb4
q5Dx/WNm3a8OiR8d/bg9/XKrK3oFGc5lT6TtEDWi1/RqfYiTdywD5pK2Ug+EoGBQfQBb
S1kAqKeka9iYqdQ665link5rBySB602ZuEekGvFDqvzdwPchlOLIkye5Ggr/RIbKcuYf
7JWehr8bSuX1RsTFTCfv6ojJozPDmEdtF6tbAxOca2bA0W6oCqesFC0e0BfdBHu9vhYK
IAapYpx7YVLaFwPAgLP6O+POU374Av+19Is9W+dgP0nhA5JvZFCiwnSmhEl9L/l9YSd4
INlw==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816;
h=mime-version:subject:from:to:message-id:sender:date
:content-transfer-encoding:dkim-signature:dkim-signature;
bh=CBs4VIi+Hgt2a2XJuW2wr7q/kVgtt7M5U3mvhqs5674=;
b=aV7Kc/3pE6pwJZPHAZwqkSVeUCmsDGs777s/ko+Zo53JiMy8nk8IDU92Zef8lDXHS8
9sfejXMiG3Sw4MgiekT8vaul8QgiXgPPnD6m3KhCif+h1AJ7k/y/scvxFeXi8l5bhVMo
8oo1ioE5Xy6UOfK7JQxECnhgQz25VaytycvtEhxB6Rtf6wkRVrrOONB9B4VS8JwU3EzG
zQ3y/Qzvisivlb50s1FBDnScBKE6eGQx15rsPxyb/hVWPDcR8VkNsmRVfNkX4n22Y3oZ
E8hVsySOo8/ht9/ImMMfPqVC9dwkHg3vZqq15t8X/+WNrWD/gq/DpElPX3urORIFmMZU
7WcA==
ARC-Authentication-Results: i=1; mx.google.com;
dkim=pass [email protected] header.s=pic header.b=VlTzhdjS;
dkim=pass [email protected] header.s=mg header.b=uysNa81o;
spf=pass (google.com: domain of bounce+a75b79.5d7be0-trevor.sawler=[email protected] designates 209.61.151.241 as permitted sender) smtp.mailfrom="bounce+a75b79.5d7be0-some-person=[email protected]"
Return-Path: [email protected]
Received: from rs241.mailgun.us (rs241.mailgun.us. [209.61.151.241])
by mx.google.com with UTF8SMTPS id c189si9473199oif.183.2021.04.11.06.46.51
for [email protected]
(version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128);
Sun, 11 Apr 2021 06:46:55 -0700 (PDT)
Received-SPF: pass (google.com: domain of bounce+a75b79.5d7be0-trevor.sawler=[email protected] designates 209.61.151.241 as permitted sender) client-ip=209.61.151.241;
Authentication-Results: mx.google.com;
dkim=pass [email protected] header.s=pic header.b=VlTzhdjS;
dkim=pass [email protected] header.s=mg header.b=uysNa81o;
spf=pass (google.com: domain of bounce+a75b79.5d7be0-trevor.sawler=[email protected] designates 209.61.151.241 as permitted sender) smtp.mailfrom="bounce+a75b79.5d7be0-trevor.sawler=[email protected]"
DKIM-Signature: a=rsa-sha256; v=1; c=relaxed/relaxed; d=mg.somedomain.com; q=dns/txt; s=pic; t=1618148815; h=Mime-Version: Content-Type: Subject: From: To: Message-Id: Sender: Date: Content-Transfer-Encoding: X-Feedback-Id; bh=CBs4VIi+Hgt2a2XJuW2wr7q/kVgtt7M5U3mvhqs5674=; b=VlTzhdjShoQVADb+knojm1mrleJz3KUO4l4Hc20/8rjfG52nYM4JD9Y2Jcc/hCqGbFUunmgd WfhyQtPSwqkw8JWBH2vqRZHyjVWvI58C4C8Wpwuhp84+NTlgO7w9ZtmnoBo8uWyr6kqfzTsS tkxC773nMW0Jb6vv2scwPKgiJm8=
DKIM-Signature: a=rsa-sha256; v=1; c=relaxed/relaxed; d=mailgun.org; q=dns/txt; s=mg; t=1618148815; h=Mime-Version: Content-Type: Subject: From: To: Message-Id: Sender: Date: Content-Transfer-Encoding: X-Feedback-Id; bh=CBs4VIi+Hgt2a2XJuW2wr7q/kVgtt7M5U3mvhqs5674=; b=uysNa81oWS2WPuiiJHGtDTSclAKGgshDcOlfgr3WM5F1LKdaiKE+d8M7bo/MKVehvZR2y1/3 D2w2D604OHt4bXiBe2OIhIxecAeTiIzdfMtLSiDArreCLSCTDlTg5PPZJoK6Ew6quk44283s nEn1iJ6Fs9d/QLnZmVBEM6EJG0c=
X-Feedback-Id: 589e0b0bcd1682225498c986:mailgun
X-Mailgun-Sending-Ip: 209.61.151.241
X-Mailgun-Sid: WyI2MDliMSIsICJ0cmV2b3Iuc2F3bGVyQGdtYWlsLmNvbSIsICI1ZDdiZTAiXQ==
Content-Transfer-Encoding: 7bit
Received: by luna.mailgun.net with HTTP; Sun, 11 Apr 2021 13:46:31 +0000
Date: Sun, 11 Apr 2021 13:46:31 +0000
Sender: contact=[email protected]
Message-Id: [email protected]
To: [email protected]
From: [email protected]
Subject: Password Reset Request
Content-Type: text/plain; charset="ascii"
Mime-Version: 1.0

Hello, world

Support SMTP

It would be great if plain old SMTP was supported.

For development, and for apps which only sends a few mails, I often use Gmail's SMTP or other SMTP servers.

Add Headers

Add option to pass extra headers to the transmission.

multipart email is not properly formatted when using smtp driver

Describe the bug
When send smtp email with both html and plain text, the Content-Type is not properly set.

To Reproduce

cfg := mail.Config{
	URL:         "smtp.gmail.com",
	FromAddress: "[email protected]",
	FromName:    "Gopher",
	Password:    "my-password",
	Port:        587,
}

mailer, err := drivers.NewSMTP(cfg)
if err != nil {
	log.Fatalln(err)
}

tx := &mail.Transmission{
	Recipients: []string{"[email protected]"},
	Subject:    "Multipart Email Example",
	HTML:       "<h1>This is the HTML Section!</h1>",
	PlainText:  "Plain text email goes here!",
}

result, err := mailer.Send(tx)

Expected behavior

From: [email protected]
To: [email protected]
Subject: Multipart Email Example
Content-Type: multipart/alternative; boundary="boundary-string"

--your-boundary
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

Plain text email goes here!

--boundary-string
Content-Type: text/html; charset="utf-8"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

<h1>This is the HTML Section!</h1>

--boundary-string--

There is a article for Multipart MIME Email Guide. And go-simple-email seems work well with it.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.