├── .env_sample ├── helpers ├── inbound │ ├── sample_data │ │ ├── default_data_with_attachments.txt │ │ ├── bad_data.txt │ │ ├── default_data.txt │ │ └── raw_data.txt │ ├── README.md │ ├── inbound_test.go │ └── inbound.go ├── mail │ └── README.md └── eventwebhook │ ├── README.md │ ├── eventwebhook.go │ └── eventwebhook_test.go ├── static └── img │ ├── github-fork.png │ └── github-sign-up.png ├── twilio_sendgrid_logo.png ├── .gitignore ├── use-cases ├── sections.md ├── attachments.md ├── custom-args.md ├── substitutions.md ├── personalizations.md ├── twilio-email.md ├── README.md ├── transactional-templates.md ├── legacy-templates.md ├── personalizations-with-mailer-helper.md ├── view-email-stats.md ├── email-activity.md ├── personalizations-without-mailer-helper.md ├── legacy-templates-with-mailer-helper.md ├── personalization-without-helper-sending-single-email-single-recipient.md ├── setup-domain-authentication.md ├── legacy-templates-without-mailer-helper.md ├── personalization-without-helper-sending-single-email-single-recipient-with-cc.md ├── personalization-without-helper-sending-single-email-single-recipient-with-cc-bcc.md ├── personalization-without-helper-sending-same-email-to-multiple-recipients.md ├── personalization-without-helper-sending-two-emails-to-two-groups-recipients-from-two-different-from-emails.md ├── personalization-without-helper-sending-single-email-to-single-recipients-with-multiple-cc-bcc.md ├── custom-args-with-mailer-helper.md ├── substitutions-with-mailer-helper.md ├── sections-with-mailer-helper.md ├── personalization-sending-single-email-single-recipient.md ├── custom-args-without-mailer-helper.md ├── substitutions-without-mailer-helper.md ├── twilio-setup.md ├── sections-without-mailer-helper.md ├── personalization-sending-single-email-single-recipient-with-cc.md ├── personalization-sending-single-email-to-multiple-recipients.md ├── personalization-sending-single-email-single-recipient-with-cc-bcc.md ├── attachments-without-mailer-helper.md ├── personalization-sending-single-email-to-single-recipients-with-multiple-cc-bcc.md ├── personalization-without-helper-sending-two-emails-to-two-groups-recipients.md ├── personalization-sending-two-emails-to-two-groups-recipients-from-two-different-from-emails.md ├── transactional-templates-without-mailer-helper.md ├── personalization-sending-two-emails-to-two-groups-recipients.md ├── attachments-with-mailer-helper.md └── transactional-templates-with-mailer-helper.md ├── go.coverage.sh ├── Makefile ├── .github └── workflows │ ├── pr-lint.yml │ └── test-and-deploy.yml ├── Dockerfile ├── examples ├── scopes │ └── scopes.go ├── stats │ └── stats.go ├── devices │ └── devices.go ├── geo │ └── geo.go ├── browsers │ └── browsers.go ├── mailboxproviders │ └── mailboxproviders.go ├── eventwebhook │ └── eventwebhook.go ├── clients │ └── clients.go ├── partnersettings │ └── partnersettings.go ├── emailactivity │ └── emailactivity.go ├── categories │ └── categories.go ├── dataresidency │ └── setRegion.go ├── alerts │ └── alerts.go ├── apikeys │ └── apikeys.go ├── accesssettings │ └── accesssettings.go ├── senders │ └── senders.go ├── mail │ └── mail.go ├── trackingsettings │ └── trackingsettings.go ├── templates │ └── templates.go ├── campaigns │ └── campaigns.go ├── ips │ └── ips.go └── asm │ └── asm.go ├── twilio_email_test.go ├── LICENSE ├── twilio_email.go ├── PULL_REQUEST_TEMPLATE.md ├── sendgrid.go ├── FIRST_TIMERS.md ├── CODE_OF_CONDUCT.md ├── base_interface.go ├── TROUBLESHOOTING.md ├── CONTRIBUTING.md └── README.md /.env_sample: -------------------------------------------------------------------------------- 1 | export SENDGRID_API_KEY='' -------------------------------------------------------------------------------- /helpers/inbound/sample_data/default_data_with_attachments.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /helpers/inbound/sample_data/bad_data.txt: -------------------------------------------------------------------------------- 1 | this is bad invalid data -------------------------------------------------------------------------------- /static/img/github-fork.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sendgrid/sendgrid-go/HEAD/static/img/github-fork.png -------------------------------------------------------------------------------- /twilio_sendgrid_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sendgrid/sendgrid-go/HEAD/twilio_sendgrid_logo.png -------------------------------------------------------------------------------- /static/img/github-sign-up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sendgrid/sendgrid-go/HEAD/static/img/github-sign-up.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | temp.go 3 | *.swp 4 | .env 5 | coverage.txt 6 | sendgrid.env 7 | .vscode 8 | prism* 9 | **/.idea/**/* 10 | -------------------------------------------------------------------------------- /use-cases/sections.md: -------------------------------------------------------------------------------- 1 | # Sections 2 | 3 | * [With Mail Helper Class](sections-with-mailer-helper.md) 4 | * [Without Mail Helper Class](sections-without-mailer-helper.md) -------------------------------------------------------------------------------- /use-cases/attachments.md: -------------------------------------------------------------------------------- 1 | # Attachments 2 | 3 | * [With Mail Helper Class](attachments-with-mailer-helper.md) 4 | * [Without Mail Helper Class](attachments-without-mailer-helper.md) -------------------------------------------------------------------------------- /use-cases/custom-args.md: -------------------------------------------------------------------------------- 1 | # CustomArgs 2 | 3 | * [With Mail Helper Class](custom-args-with-mailer-helper.md) 4 | * [Without Mail Helper Class](custom-args-without-mailer-helper.md) -------------------------------------------------------------------------------- /use-cases/substitutions.md: -------------------------------------------------------------------------------- 1 | # Substitutions 2 | 3 | * [With Mail Helper Class](substitutions-with-mailer-helper.md) 4 | * [Without Mail Helper Class](substitutions-without-mailer-helper.md) -------------------------------------------------------------------------------- /use-cases/personalizations.md: -------------------------------------------------------------------------------- 1 | # Personalizations 2 | 3 | * [With Mail Helper Class](personalizations-with-mailer-helper.md) 4 | * [Without Mail Helper Class](personalizations-without-mailer-helper.md) -------------------------------------------------------------------------------- /go.coverage.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | echo > coverage.txt 5 | 6 | for d in $(go list ./... | grep -v -E '/vendor|/examples|/docker'); do 7 | go test -coverprofile=profile.out -covermode=atomic "$d" 8 | if [ -f profile.out ]; then 9 | cat profile.out >> coverage.txt 10 | rm profile.out 11 | fi 12 | done 13 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: test install test-integ test-docker 2 | 3 | install: 4 | go get -t -v ./... 5 | 6 | test: 7 | ./go.coverage.sh 8 | bash -c 'diff -u <(echo -n) <(gofmt -d -s .)' 9 | 10 | test-integ: test 11 | 12 | version ?= latest 13 | test-docker: 14 | curl -s https://raw.githubusercontent.com/sendgrid/sendgrid-oai/HEAD/prism/prism.sh -o prism.sh 15 | version=$(version) bash ./prism.sh 16 | -------------------------------------------------------------------------------- /.github/workflows/pr-lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint PR 2 | on: 3 | pull_request_target: 4 | types: [ opened, edited, synchronize, reopened ] 5 | 6 | jobs: 7 | validate: 8 | name: Validate title 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: amannn/action-semantic-pull-request@v4 12 | with: 13 | types: chore docs fix feat test misc 14 | env: 15 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 16 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.21.11 2 | 3 | ENV GO111MODULE 'off' 4 | 5 | COPY prism/prism/nginx/cert.crt /usr/local/share/ca-certificates/cert.crt 6 | RUN update-ca-certificates 7 | 8 | WORKDIR /go/src/github.com/sendgrid/sendgrid-go 9 | COPY . . 10 | 11 | RUN make install 12 | 13 | # Use the last version of testify that works for older go versions, and then 14 | # re-install to update dependencies. 15 | RUN (cd /go/src/github.com/stretchr/testify && git checkout v1.6.0) 16 | RUN make install 17 | -------------------------------------------------------------------------------- /use-cases/twilio-email.md: -------------------------------------------------------------------------------- 1 | First, follow the [Twilio Setup](twilio-setup.md) guide for creating a Twilio account and setting up environment variables with the proper credentials. 2 | 3 | Then, initialize the Twilio Email Client. 4 | 5 | ```go 6 | mailClient := NewTwilioEmailSendClient(os.Getenv("TWILIO_API_KEY"), os.Getenv("TWILIO_API_SECRET")) 7 | 8 | // or 9 | 10 | mailClient := NewTwilioEmailSendClient(os.Getenv("TWILIO_ACCOUNT_SID"), os.Getenv("TWILIO_AUTH_TOKEN")) 11 | ``` 12 | 13 | This sets the client to use Twilio Auth and the Twilio Email API. 14 | -------------------------------------------------------------------------------- /examples/scopes/scopes.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | 8 | "github.com/sendgrid/sendgrid-go" 9 | ) 10 | 11 | // Retrievealistofscopesforwhichthisuserhasaccess : Retrieve a list of scopes for which this user has access. 12 | // GET /scopes 13 | func Retrievealistofscopesforwhichthisuserhasaccess() { 14 | apiKey := os.Getenv("SENDGRID_API_KEY") 15 | host := "https://api.sendgrid.com" 16 | request := sendgrid.GetRequest(apiKey, "/v3/scopes", host) 17 | request.Method = "GET" 18 | response, err := sendgrid.API(request) 19 | if err != nil { 20 | log.Println(err) 21 | } else { 22 | fmt.Println(response.StatusCode) 23 | fmt.Println(response.Body) 24 | fmt.Println(response.Headers) 25 | } 26 | } 27 | 28 | func main() { 29 | // add your function calls here 30 | } 31 | -------------------------------------------------------------------------------- /helpers/mail/README.md: -------------------------------------------------------------------------------- 1 | **This helper allows you to quickly and easily build a Mail object for sending email through Twilio SendGrid.** 2 | 3 | ## Dependencies 4 | 5 | - [rest](https://github.com/sendgrid/rest) 6 | 7 | # Quick Start 8 | 9 | Run the [example](../../examples/helpers/mail/example.go) (make sure you have set your environment variable to include your SENDGRID_API_KEY). 10 | 11 | ```bash 12 | go run examples/helpers/mail/example.go 13 | ``` 14 | 15 | ## Usage 16 | 17 | - See the [example](../../examples/helpers/mail/example.go) for a complete working example. 18 | - [Documentation](https://sendgrid.com/docs/API_Reference/Web_API_v3/Mail/index.html) 19 | 20 | ## Test 21 | 22 | ```bash 23 | go test ./... -v 24 | ``` 25 | 26 | or 27 | 28 | ```bash 29 | cd helpers/mail 30 | go test -v 31 | ``` 32 | -------------------------------------------------------------------------------- /use-cases/README.md: -------------------------------------------------------------------------------- 1 | This documentation provides examples for specific Twilio SendGrid use cases. Please [open an issue](https://github.com/sendgrid/sendgrid-go/issues) or make a pull request for any use cases you would like us to document here. Thank you! 2 | 3 | # Email Use Cases 4 | * [Transactional Templates](transactional-templates.md) 5 | * [Legacy Templates](legacy-templates.md) 6 | * [CustomArgs](custom-args.md) 7 | * [Personalizations](personalizations.md) 8 | * [Substitutions](substitutions.md) 9 | * [Sections](sections.md) 10 | * [Attachments](attachments.md) 11 | * [How to View Email Statistics](view-email-stats.md) 12 | * [How to Setup a Domain Authentication](setup-domain-authentication.md) 13 | 14 | # Twilio Use Cases 15 | * [Twilio Setup](twilio-setup.md) 16 | * [Send an Email With Twilio Email (Pilot)](twilio-email.md) 17 | -------------------------------------------------------------------------------- /helpers/eventwebhook/README.md: -------------------------------------------------------------------------------- 1 | **This helper allows you to quickly and easily enable/disable SecureWebhook feature or get the public key through Twilio SendGrid.** 2 | 3 | ## Dependencies 4 | 5 | - [rest](https://github.com/sendgrid/rest) 6 | 7 | # Quick Start 8 | 9 | Run the [example](../../examples/eventwebhook/eventwebhook.go) (make sure you have set your environment variable to include your SENDGRID_API_KEY). 10 | ```bash 11 | go run examples/eventwebhook/eventwebhook.go 12 | ``` 13 | 14 | ## Usage 15 | 16 | - See the [example](../../examples/eventwebhook/eventwebhook.go) for a complete working example. 17 | - [Documentation](https://sendgrid.com/docs/for-developers/tracking-events/) 18 | 19 | ## Test 20 | 21 | ```bash 22 | go test ./... -v 23 | ``` 24 | 25 | or 26 | 27 | ```bash 28 | cd helpers/eventwebhook 29 | go test -v 30 | ``` 31 | -------------------------------------------------------------------------------- /use-cases/transactional-templates.md: -------------------------------------------------------------------------------- 1 | # Transactional Templates 2 | For this example, we assume you have created a [dynamic transactional template](https://sendgrid.com/docs/ui/sending-email/how-to-send-an-email-with-dynamic-transactional-templates/) in the UI or via the API. Following is the dynamic template data we used for testing. 3 | 4 | Template ID (replace with your own): 5 | 6 | ```text 7 | d-c6dcf1f72bdd4beeb15a9aa6c72fcd2c 8 | ``` 9 | 10 | [Template Body](https://github.com/sendgrid/email-templates/blob/HEAD/dynamic-templates/receipt/receipt.html) 11 | 12 | [Template Data](https://github.com/sendgrid/email-templates/blob/HEAD/dynamic-templates/receipt/receipt_data.json) 13 | 14 | * [With Mail Helper Class](transactional-templates-with-mailer-helper.md) 15 | * [Without Mail Helper Class](transactional-templates-without-mailer-helper.md) 16 | -------------------------------------------------------------------------------- /use-cases/legacy-templates.md: -------------------------------------------------------------------------------- 1 | # Legacy Templates 2 | 3 | For this example, we assume you have created a [legacy transactional template](https://sendgrid.com/docs/User_Guide/Transactional_Templates/index.html) in the UI or via the API. Following is the template content we used for testing. 4 | 5 | Template ID (replace with your own): 6 | 7 | ```text 8 | 13b8f94f-bcae-4ec6-b752-70d6cb59f932 9 | ``` 10 | 11 | Email Subject: 12 | 13 | ```text 14 | <%subject%> 15 | ``` 16 | 17 | Template Body: 18 | 19 | ```html 20 | 21 | 22 | 23 | 24 | 25 | Hello -name-, 26 |

27 | I'm glad you are trying out the template feature! 28 |

29 | <%body%> 30 |

31 | I hope you are having a great day in -city- :) 32 |

33 | 34 | 35 | ``` 36 | 37 | * [With Mail Helper Class](legacy-templates-with-mailer-helper.md) 38 | * [Without Mail Helper Class](legacy-templates-without-mailer-helper.md) 39 | -------------------------------------------------------------------------------- /examples/stats/stats.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | 8 | "github.com/sendgrid/sendgrid-go" 9 | ) 10 | 11 | // Retrieveglobalemailstatistics : Retrieve global email statistics 12 | // GET /stats 13 | func Retrieveglobalemailstatistics() { 14 | apiKey := os.Getenv("SENDGRID_API_KEY") 15 | host := "https://api.sendgrid.com" 16 | request := sendgrid.GetRequest(apiKey, "/v3/stats", host) 17 | request.Method = "GET" 18 | queryParams := make(map[string]string) 19 | queryParams["aggregated_by"] = "day" 20 | queryParams["limit"] = "1" 21 | queryParams["start_date"] = "2016-01-01" 22 | queryParams["end_date"] = "2016-04-01" 23 | queryParams["offset"] = "1" 24 | request.QueryParams = queryParams 25 | response, err := sendgrid.API(request) 26 | if err != nil { 27 | log.Println(err) 28 | } else { 29 | fmt.Println(response.StatusCode) 30 | fmt.Println(response.Body) 31 | fmt.Println(response.Headers) 32 | } 33 | } 34 | 35 | func main() { 36 | // add your function calls here 37 | } 38 | -------------------------------------------------------------------------------- /examples/devices/devices.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | 8 | "github.com/sendgrid/sendgrid-go" 9 | ) 10 | 11 | // Retrieveemailstatisticsbydevicetype : Retrieve email statistics by device type. 12 | // GET /devices/stats 13 | func Retrieveemailstatisticsbydevicetype() { 14 | apiKey := os.Getenv("SENDGRID_API_KEY") 15 | host := "https://api.sendgrid.com" 16 | request := sendgrid.GetRequest(apiKey, "/v3/devices/stats", host) 17 | request.Method = "GET" 18 | queryParams := make(map[string]string) 19 | queryParams["aggregated_by"] = "day" 20 | queryParams["limit"] = "1" 21 | queryParams["start_date"] = "2016-01-01" 22 | queryParams["end_date"] = "2016-04-01" 23 | queryParams["offset"] = "1" 24 | request.QueryParams = queryParams 25 | response, err := sendgrid.API(request) 26 | if err != nil { 27 | log.Println(err) 28 | } else { 29 | fmt.Println(response.StatusCode) 30 | fmt.Println(response.Body) 31 | fmt.Println(response.Headers) 32 | } 33 | } 34 | 35 | func main() { 36 | // add your function calls here 37 | } 38 | -------------------------------------------------------------------------------- /use-cases/personalizations-with-mailer-helper.md: -------------------------------------------------------------------------------- 1 | ## Personalizations - With Mail Helper Class 2 | 3 | * [Sending a Single Email to a Single Recipient](personalization-sending-single-email-single-recipient.md) 4 | * [Sending a Single Email to a Single Recipient with a CC](personalization-sending-single-email-single-recipient-with-cc.md) 5 | * [Sending a Single Email to a Single Recipient with a CC and a BCC](personalization-sending-single-email-single-recipient-with-cc-bcc.md) 6 | * [Sending a Single Email to Multiple Recipients](personalization-sending-single-email-to-multiple-recipients.md) 7 | * [Sending a Single Email to a Single Recipient with Multiple CCs/BCCs](personalization-sending-single-email-to-single-recipients-with-multiple-cc-bcc.md) 8 | * [Sending Two Different Emails to Two Different Groups of Recipients](personalization-sending-two-emails-to-two-groups-recipients.md) 9 | * [Sending Two Different Emails to Two Different Groups of Recipients from two different From email addresses ](personalization-sending-two-emails-to-two-groups-recipients-from-two-different-from-emails.md) -------------------------------------------------------------------------------- /use-cases/view-email-stats.md: -------------------------------------------------------------------------------- 1 | ## How to View Email Statistics 2 | 3 | You can find documentation for how to view your email statistics via the UI [here](https://app.sendgrid.com/statistics). 4 | To view Email Statistics via the API: 5 | ``` 6 | package main 7 | 8 | import ( 9 | "fmt" 10 | "log" 11 | "os" 12 | 13 | "github.com/sendgrid/sendgrid-go" 14 | ) 15 | 16 | func main() { 17 | apiKey := os.Getenv("SENDGRID_API_KEY") 18 | host := "https://api.sendgrid.com" 19 | request := sendgrid.GetRequest(apiKey, "/v3/stats", host) 20 | request.Method = "GET" 21 | queryParams := make(map[string]string) 22 | queryParams["aggregated_by"] = "day" 23 | queryParams["limit"] = "1" 24 | queryParams["start_date"] = "2017-01-01" 25 | queryParams["end_date"] = "2017-10-12" 26 | queryParams["offset"] = "1" 27 | request.QueryParams = queryParams 28 | response, err := sendgrid.API(request) 29 | if err != nil { 30 | log.Println(err) 31 | } else { 32 | fmt.Println(response.StatusCode) 33 | fmt.Println(response.Body) 34 | fmt.Println(response.Headers) 35 | } 36 | } 37 | ``` -------------------------------------------------------------------------------- /twilio_email_test.go: -------------------------------------------------------------------------------- 1 | package sendgrid 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "net/http/httptest" 7 | "strings" 8 | "testing" 9 | 10 | "github.com/stretchr/testify/assert" 11 | "github.com/stretchr/testify/require" 12 | ) 13 | 14 | func TestNewTwilioEmailSendClient(t *testing.T) { 15 | mailClient := NewTwilioEmailSendClient("username", "password") 16 | assert.Equal(t, "https://email.twilio.com/v3/mail/send", mailClient.BaseURL) 17 | assert.Equal(t, "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", mailClient.Headers["Authorization"]) 18 | } 19 | 20 | func TestGetTwilioEmailRequest(t *testing.T) { 21 | fakeServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 22 | _, _ = fmt.Fprintln(w, "{\"message\": \"success\"}") 23 | })) 24 | defer fakeServer.Close() 25 | 26 | request := GetTwilioEmailRequest(TwilioEmailOptions{ 27 | Username: "username", 28 | Password: "password", 29 | Host: fakeServer.URL, 30 | }) 31 | response, err := MakeRequest(request) 32 | require.NoError(t, err) 33 | assert.True(t, strings.Contains(response.Body, "success")) 34 | } 35 | -------------------------------------------------------------------------------- /use-cases/email-activity.md: -------------------------------------------------------------------------------- 1 | ## Email activity filter 2 | ### To find the email sent to `testing@sendgrid.net` 3 | ```go 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "log" 9 | "net/url" 10 | "os" 11 | 12 | "github.com/sendgrid/sendgrid-go" 13 | ) 14 | 15 | func main() { 16 | apiKey := os.Getenv("YOUR_SENDGRID_APIKEY") 17 | host := "https://api.sendgrid.com" 18 | request := sendgrid.GetRequest(apiKey, "/v3/messages", host) 19 | request.Method = "GET" 20 | 21 | filterKey := "to_email" 22 | filterOperator := url.QueryEscape("=") 23 | filterValue := "testing@sendgrid.net" 24 | filterValue = url.QueryEscape(fmt.Sprintf("\"%s\"", filterValue)) 25 | 26 | queryParams := make(map[string]string) 27 | queryParams["query"] = fmt.Sprintf("%s%s%s", filterKey, filterOperator, filterValue) 28 | queryParams["limit"] = "1" 29 | request.QueryParams = queryParams 30 | 31 | response, err := sendgrid.API(request) 32 | if err != nil { 33 | log.Println(err) 34 | } else { 35 | fmt.Println(response.StatusCode) 36 | fmt.Println(response.Body) 37 | fmt.Println(response.Headers) 38 | } 39 | } 40 | ``` 41 | -------------------------------------------------------------------------------- /examples/geo/geo.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | 8 | "github.com/sendgrid/sendgrid-go" 9 | ) 10 | 11 | // Retrieveemailstatisticsbycountryandstateprovince : Retrieve email statistics by country and state/province. 12 | // GET /geo/stats 13 | func Retrieveemailstatisticsbycountryandstateprovince() { 14 | apiKey := os.Getenv("SENDGRID_API_KEY") 15 | host := "https://api.sendgrid.com" 16 | request := sendgrid.GetRequest(apiKey, "/v3/geo/stats", host) 17 | request.Method = "GET" 18 | queryParams := make(map[string]string) 19 | queryParams["end_date"] = "2016-04-01" 20 | queryParams["country"] = "US" 21 | queryParams["aggregated_by"] = "day" 22 | queryParams["limit"] = "1" 23 | queryParams["offset"] = "1" 24 | queryParams["start_date"] = "2016-01-01" 25 | request.QueryParams = queryParams 26 | response, err := sendgrid.API(request) 27 | if err != nil { 28 | log.Println(err) 29 | } else { 30 | fmt.Println(response.StatusCode) 31 | fmt.Println(response.Body) 32 | fmt.Println(response.Headers) 33 | } 34 | } 35 | 36 | func main() { 37 | // add your function calls here 38 | } 39 | -------------------------------------------------------------------------------- /examples/browsers/browsers.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | 8 | sendgrid "github.com/sendgrid/sendgrid-go" 9 | ) 10 | 11 | // Retrieveemailstatisticsbybrowser : Retrieve email statistics by browser. 12 | // GET /browsers/stats 13 | func Retrieveemailstatisticsbybrowser() { 14 | apiKey := os.Getenv("SENDGRID_API_KEY") 15 | host := "https://api.sendgrid.com" 16 | request := sendgrid.GetRequest(apiKey, "/v3/browsers/stats", host) 17 | request.Method = "GET" 18 | queryParams := make(map[string]string) 19 | queryParams["end_date"] = "2016-04-01" 20 | queryParams["aggregated_by"] = "day" 21 | queryParams["browsers"] = "test_string" 22 | queryParams["limit"] = "test_string" 23 | queryParams["offset"] = "test_string" 24 | queryParams["start_date"] = "2016-01-01" 25 | request.QueryParams = queryParams 26 | response, err := sendgrid.API(request) 27 | if err != nil { 28 | log.Println(err) 29 | } else { 30 | fmt.Println(response.StatusCode) 31 | fmt.Println(response.Body) 32 | fmt.Println(response.Headers) 33 | } 34 | } 35 | 36 | func main() { 37 | // add your function calls here 38 | } 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (C) 2025, Twilio SendGrid, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/mailboxproviders/mailboxproviders.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | 8 | "github.com/sendgrid/sendgrid-go" 9 | ) 10 | 11 | // Retrieveemailstatisticsbymailboxprovider : Retrieve email statistics by mailbox provider. 12 | // GET /mailbox_providers/stats 13 | func Retrieveemailstatisticsbymailboxprovider() { 14 | apiKey := os.Getenv("SENDGRID_API_KEY") 15 | host := "https://api.sendgrid.com" 16 | request := sendgrid.GetRequest(apiKey, "/v3/mailbox_providers/stats", host) 17 | request.Method = "GET" 18 | queryParams := make(map[string]string) 19 | queryParams["end_date"] = "2016-04-01" 20 | queryParams["mailbox_providers"] = "test_string" 21 | queryParams["aggregated_by"] = "day" 22 | queryParams["limit"] = "1" 23 | queryParams["offset"] = "1" 24 | queryParams["start_date"] = "2016-01-01" 25 | request.QueryParams = queryParams 26 | response, err := sendgrid.API(request) 27 | if err != nil { 28 | log.Println(err) 29 | } else { 30 | fmt.Println(response.StatusCode) 31 | fmt.Println(response.Body) 32 | fmt.Println(response.Headers) 33 | } 34 | } 35 | 36 | func main() { 37 | // add your function calls here 38 | } 39 | -------------------------------------------------------------------------------- /use-cases/personalizations-without-mailer-helper.md: -------------------------------------------------------------------------------- 1 | ## Personalizations - Without Mail Helper Class 2 | 3 | * [Sending a Single Email to a Single Recipient](personalization-without-helper-sending-single-email-single-recipient.md) 4 | * [Sending a Single Email to a Single Recipient with a CC](personalization-without-helper-sending-single-email-single-recipient-with-cc.md) 5 | * [Sending a Single Email to a Single Recipient with a CC and a BCC](personalization-without-helper-sending-single-email-single-recipient-with-cc-bcc.md) 6 | * [Sending the same Email to Multiple Recipients](personalization-without-helper-sending-same-email-to-multiple-recipients.md) 7 | * [Sending a Single Email to a Single Recipient with Multiple CCs/BCCs](personalization-without-helper-sending-single-email-to-single-recipients-with-multiple-cc-bcc.md) 8 | * [Sending Two Different Emails to Two Different Groups of Recipients](personalization-without-helper-sending-two-emails-to-two-groups-recipients.md) 9 | * [Sending Two Different Emails to Two Different Groups of Recipients from two different From email addresses](personalization-without-helper-sending-two-emails-to-two-groups-recipients-from-two-different-from-emails.md) -------------------------------------------------------------------------------- /use-cases/legacy-templates-with-mailer-helper.md: -------------------------------------------------------------------------------- 1 | ## Legacy Templates - With Mail Helper Class 2 | 3 | ```go 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "log" 9 | "os" 10 | 11 | "github.com/sendgrid/sendgrid-go" 12 | "github.com/sendgrid/sendgrid-go/helpers/mail" 13 | ) 14 | 15 | func main() { 16 | from := mail.NewEmail("Example User", "test@example.com") 17 | subject := "I'm replacing the subject tag" 18 | to := mail.NewEmail("Example User", "test@example.com") 19 | content := mail.NewContent("text/html", "I'm replacing the body tag") 20 | m := mail.NewV3MailInit(from, subject, to, content) 21 | m.Personalizations[0].SetSubstitution("-name-", "Example User") 22 | m.Personalizations[0].SetSubstitution("-city-", "Denver") 23 | m.SetTemplateID("13b8f94f-bcae-4ec6-b752-70d6cb59f932") 24 | 25 | request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KEY"), "/v3/mail/send", "https://api.sendgrid.com") 26 | request.Method = "POST" 27 | request.Body = mail.GetRequestBody(m) 28 | response, err := sendgrid.API(request) 29 | if err != nil { 30 | log.Println(err) 31 | } else { 32 | fmt.Println(response.StatusCode) 33 | fmt.Println(response.Body) 34 | fmt.Println(response.Headers) 35 | } 36 | } 37 | ``` -------------------------------------------------------------------------------- /use-cases/personalization-without-helper-sending-single-email-single-recipient.md: -------------------------------------------------------------------------------- 1 | ## Personalization (without helper) - Sending A Single Email to a Single Recipient 2 | 3 | ```go 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "log" 9 | "os" 10 | 11 | "github.com/sendgrid/sendgrid-go" 12 | ) 13 | 14 | func main() { 15 | request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KEY"), "/v3/mail/send", "https://api.sendgrid.com") 16 | request.Method = "POST" 17 | request.Body = []byte(`{ 18 | "personalizations": [{ 19 | "to": [{ 20 | "email": "test1@example.com" 21 | }], 22 | "substitutions": { 23 | "%fname%": "recipient", 24 | "%CustomerID%": "CUSTOMER ID GOES HERE" 25 | }, 26 | "subject": "YOUR SUBJECT LINE GOES HERE" 27 | }], 28 | "from": { 29 | "email": "test@example.com" 30 | }, 31 | "content": [ 32 | { 33 | "type": "text/html", 34 | "value": "

%fname% : %CustomerID% - Personalizations are awesome!

" 35 | } 36 | ] 37 | }`) 38 | response, err := sendgrid.API(request) 39 | if err != nil { 40 | log.Println(err) 41 | } else { 42 | fmt.Println(response.StatusCode) 43 | fmt.Println(response.Body) 44 | fmt.Println(response.Headers) 45 | } 46 | } 47 | ``` -------------------------------------------------------------------------------- /twilio_email.go: -------------------------------------------------------------------------------- 1 | package sendgrid 2 | 3 | import ( 4 | "encoding/base64" 5 | 6 | "github.com/sendgrid/rest" 7 | ) 8 | 9 | // TwilioEmailOptions for GetTwilioEmailRequest 10 | type TwilioEmailOptions struct { 11 | Username string 12 | Password string 13 | Endpoint string 14 | Host string 15 | } 16 | 17 | // NewTwilioEmailSendClient constructs a new Twilio Email client given a username and password 18 | func NewTwilioEmailSendClient(username, password string) *Client { 19 | request := GetTwilioEmailRequest(TwilioEmailOptions{Username: username, Password: password, Endpoint: "/v3/mail/send"}) 20 | request.Method = "POST" 21 | return &Client{request} 22 | } 23 | 24 | // GetTwilioEmailRequest create Request 25 | // @return [Request] a default request object 26 | func GetTwilioEmailRequest(twilioEmailOptions TwilioEmailOptions) rest.Request { 27 | credentials := twilioEmailOptions.Username + ":" + twilioEmailOptions.Password 28 | encodedCreds := base64.StdEncoding.EncodeToString([]byte(credentials)) 29 | 30 | options := options{ 31 | Auth: "Basic " + encodedCreds, 32 | Endpoint: twilioEmailOptions.Endpoint, 33 | Host: twilioEmailOptions.Host, 34 | } 35 | 36 | if options.Host == "" { 37 | options.Host = "https://email.twilio.com" 38 | } 39 | 40 | return requestNew(options) 41 | } 42 | -------------------------------------------------------------------------------- /use-cases/setup-domain-authentication.md: -------------------------------------------------------------------------------- 1 | ## How to Setup a Domain Authentication 2 | 3 | You can find documentation for how to setup a domain authentication via the UI [here](https://sendgrid.com/docs/ui/account-and-settings/how-to-set-up-domain-authentication/). 4 | Find more information about all of Twilio SendGrid's authentication related documentation [here](https://sendgrid.com/docs/ui/account-and-settings/). 5 | 6 | To create a Domain authentication Via the API: 7 | ``` 8 | package main 9 | 10 | import ( 11 | "fmt" 12 | "log" 13 | "os" 14 | 15 | "github.com/sendgrid/sendgrid-go" 16 | ) 17 | 18 | func main() { 19 | apiKey := os.Getenv("SENDGRID_API_KEY") 20 | host := "https://api.sendgrid.com" 21 | request := sendgrid.GetRequest(apiKey, "/v3/whitelabel/domains", host) 22 | request.Method = "POST" 23 | request.Body = []byte(` { 24 | "automatic_security": false, 25 | "custom_spf": true, 26 | "default": true, 27 | "domain": "example.com", 28 | "ips": [ 29 | "192.168.1.1", 30 | "192.168.1.2" 31 | ], 32 | "subdomain": "SUBDOMAIN", 33 | "username": "YOUR_SENDGRID_SUBUSER_NAME" 34 | }`) 35 | response, err := sendgrid.API(request) 36 | if err != nil { 37 | log.Println(err) 38 | } else { 39 | fmt.Println(response.StatusCode) 40 | fmt.Println(response.Body) 41 | fmt.Println(response.Headers) 42 | } 43 | } 44 | ``` 45 | -------------------------------------------------------------------------------- /use-cases/legacy-templates-without-mailer-helper.md: -------------------------------------------------------------------------------- 1 | ## Without Mail Helper Class 2 | 3 | ```go 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "log" 9 | "os" 10 | 11 | "github.com/sendgrid/sendgrid-go" 12 | ) 13 | 14 | func main() { 15 | request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KEY"), "/v3/mail/send", "https://api.sendgrid.com") 16 | request.Method = "POST" 17 | request.Body = []byte(` { 18 | "personalizations": [ 19 | { 20 | "to": [ 21 | { 22 | "email": "test@example.com" 23 | } 24 | ], 25 | "subject": "I'm replacing the subject tag", 26 | "substitutions": { 27 | "-name-": "Example User", 28 | "-city-": "Denver" 29 | }, 30 | } 31 | ], 32 | "from": { 33 | "email": "test@example.com" 34 | }, 35 | "content": [ 36 | { 37 | "type": "text/html", 38 | "value": "I'm replacing the body tag" 39 | } 40 | ], 41 | "template_id": "13b8f94f-bcae-4ec6-b752-70d6cb59f932" 42 | }`) 43 | response, err := sendgrid.API(request) 44 | if err != nil { 45 | log.Println(err) 46 | } else { 47 | fmt.Println(response.StatusCode) 48 | fmt.Println(response.Body) 49 | fmt.Println(response.Headers) 50 | } 51 | } 52 | ``` -------------------------------------------------------------------------------- /use-cases/personalization-without-helper-sending-single-email-single-recipient-with-cc.md: -------------------------------------------------------------------------------- 1 | ### Personalization (without helper) - Sending a Single Email to a Single Recipient With a CC 2 | 3 | ```go 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "log" 9 | "os" 10 | 11 | "github.com/sendgrid/sendgrid-go" 12 | ) 13 | 14 | func main() { 15 | request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KEY"), "/v3/mail/send", "https://api.sendgrid.com") 16 | request.Method = "POST" 17 | request.Body = []byte(`{ 18 | "personalizations": [{ 19 | "to": [{ 20 | "email": "recipient1@example.com" 21 | }], 22 | "cc": [{ 23 | "email": "recipient2@example.com" 24 | }], 25 | "substitutions": { 26 | "%fname%": "recipient", 27 | "%CustomerID%": "CUSTOMER ID GOES HERE" 28 | }, 29 | "subject": "YOUR SUBJECT LINE GOES HERE" 30 | }], 31 | "from": { 32 | "email": "test@example.com" 33 | }, 34 | "content": [ 35 | { 36 | "type": "text/html", 37 | "value": "

%fname% : %CustomerID% - Personalizations are awesome!

" 38 | } 39 | ] 40 | }`) 41 | response, err := sendgrid.API(request) 42 | if err != nil { 43 | log.Println(err) 44 | } else { 45 | fmt.Println(response.StatusCode) 46 | fmt.Println(response.Body) 47 | fmt.Println(response.Headers) 48 | } 49 | } 50 | ``` -------------------------------------------------------------------------------- /use-cases/personalization-without-helper-sending-single-email-single-recipient-with-cc-bcc.md: -------------------------------------------------------------------------------- 1 | ### Sending a Single Email to a Single Recipient With a CC and a BCC 2 | 3 | ```go 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "log" 9 | "os" 10 | 11 | "github.com/sendgrid/sendgrid-go" 12 | ) 13 | 14 | func main() { 15 | request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KEY"), "/v3/mail/send", "https://api.sendgrid.com") 16 | request.Method = "POST" 17 | request.Body = []byte(`{ 18 | "personalizations": [{ 19 | "to": [{ 20 | "email": "recipient1@example.com" 21 | }], 22 | "cc": [{ 23 | "email": "recipient2@example.com" 24 | }], 25 | "bcc": [{ 26 | "email": "recipient3@example.com" 27 | }], 28 | "substitutions": { 29 | "%fname%": "recipient", 30 | "%CustomerID%": "CUSTOMER ID GOES HERE" 31 | } 32 | }], 33 | "from": { 34 | "email": "test@example.com" 35 | }, 36 | "content": [ 37 | { 38 | "type": "text/html", 39 | "value": "

%fname% : %CustomerID% - Personalizations are awesome!

" 40 | } 41 | ] 42 | }`) 43 | response, err := sendgrid.API(request) 44 | if err != nil { 45 | log.Println(err) 46 | } else { 47 | fmt.Println(response.StatusCode) 48 | fmt.Println(response.Body) 49 | fmt.Println(response.Headers) 50 | } 51 | } 52 | ``` -------------------------------------------------------------------------------- /use-cases/personalization-without-helper-sending-same-email-to-multiple-recipients.md: -------------------------------------------------------------------------------- 1 | ### Personalization (without helper) - Sending the same Email to Multiple Recipients 2 | 3 | ```go 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "log" 9 | "os" 10 | 11 | "github.com/sendgrid/sendgrid-go" 12 | ) 13 | 14 | func main() { 15 | request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KEY"), "/v3/mail/send", "https://api.sendgrid.com") 16 | request.Method = "POST" 17 | request.Body = []byte(`{ 18 | "personalizations": [{ 19 | "to": [{ 20 | "email": "recipient1@example.com" 21 | }, { 22 | "email": "recipient2@example.com" 23 | }, { 24 | "email": "recipient3@example.com" 25 | }], 26 | "substitutions": { 27 | "%fname%": "recipient", 28 | "%CustomerID%": "CUSTOMER ID GOES HERE" 29 | }, 30 | "subject": "YOUR SUBJECT LINE GOES HERE" 31 | }], 32 | "from": { 33 | "email": "test@example.com" 34 | }, 35 | "content": [ 36 | { 37 | "type": "text/html", 38 | "value": "

%fname% : %CustomerID% - Personalizations are awesome!

" 39 | } 40 | ] 41 | }`) 42 | response, err := sendgrid.API(request) 43 | if err != nil { 44 | log.Println(err) 45 | } else { 46 | fmt.Println(response.StatusCode) 47 | fmt.Println(response.Body) 48 | fmt.Println(response.Headers) 49 | } 50 | } 51 | ``` -------------------------------------------------------------------------------- /use-cases/personalization-without-helper-sending-two-emails-to-two-groups-recipients-from-two-different-from-emails.md: -------------------------------------------------------------------------------- 1 | ### Personalization (without helper) - Sending Two Different Emails to Two Different Groups of Recipients from two different From email address 2 | 3 | ```go 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "log" 9 | "os" 10 | 11 | "github.com/sendgrid/sendgrid-go" 12 | ) 13 | 14 | func main() { 15 | request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KEY"), "/v3/mail/send", "https://api.sendgrid.com") 16 | request.Method = "POST" 17 | request.Body = []byte(`{ 18 | "personalizations": [{ 19 | "to": [{ 20 | "email": "recipient1@example.com" 21 | }], 22 | "subject": "YOUR SUBJECT LINE GOES HERE" 23 | }, { 24 | "to": [{ 25 | "email": "recipient2@example.com" 26 | }], 27 | "from": { 28 | "email": "sender2@example.com" 29 | }, 30 | "subject": "YOUR OTHER SUBJECT LINE GOES HERE" 31 | }], 32 | "from": { 33 | "email": "defaultSender@example.com" 34 | }, 35 | "content": [ 36 | { 37 | "type": "text/html", 38 | "value": "

Personalizations are awesome!

" 39 | } 40 | ] 41 | }`) 42 | response, err := sendgrid.API(request) 43 | if err != nil { 44 | log.Println(err) 45 | } else { 46 | fmt.Println(response.StatusCode) 47 | fmt.Println(response.Body) 48 | fmt.Println(response.Headers) 49 | } 50 | } 51 | ``` -------------------------------------------------------------------------------- /use-cases/personalization-without-helper-sending-single-email-to-single-recipients-with-multiple-cc-bcc.md: -------------------------------------------------------------------------------- 1 | ### Personalization (without helper) - Sending a Single Email to a Single Recipient with Multiple CCs/BCCs 2 | 3 | ```go 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "log" 9 | "os" 10 | 11 | "github.com/sendgrid/sendgrid-go" 12 | ) 13 | 14 | func main() { 15 | request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KEY"), "/v3/mail/send", "https://api.sendgrid.com") 16 | request.Method = "POST" 17 | request.Body = []byte(`{ 18 | "personalizations": [{ 19 | "to": [{ 20 | "email": "recipient1@example.com" 21 | }], 22 | "cc": [{ 23 | "email": "recipient2@example.com" 24 | }, { 25 | "email": "recipient3@example.com" 26 | }, { 27 | "email": "recipient4@example.com" 28 | }], 29 | "substitutions": { 30 | "%fname%": "recipient", 31 | "%CustomerID%": "CUSTOMER ID GOES HERE" 32 | }, 33 | "subject": "YOUR SUBJECT LINE GOES HERE" 34 | }], 35 | "from": { 36 | "email": "test@example.com" 37 | }, 38 | "content": [ 39 | { 40 | "type": "text/html", 41 | "value": "

%fname% : %CustomerID% - Personalizations are awesome!

" 42 | } 43 | ] 44 | }`) 45 | response, err := sendgrid.API(request) 46 | if err != nil { 47 | log.Println(err) 48 | } else { 49 | fmt.Println(response.StatusCode) 50 | fmt.Println(response.Body) 51 | fmt.Println(response.Headers) 52 | } 53 | } 54 | ``` -------------------------------------------------------------------------------- /use-cases/custom-args-with-mailer-helper.md: -------------------------------------------------------------------------------- 1 | ## CustomArgs - With Mail Helper Class 2 | 3 | ```go 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "log" 9 | "os" 10 | 11 | "github.com/sendgrid/sendgrid-go" 12 | "github.com/sendgrid/sendgrid-go/helpers/mail" 13 | ) 14 | 15 | func main() { 16 | from := mail.NewEmail("Example User", "test@example.com") 17 | subject := "CustomArgs can be fun" 18 | to := mail.NewEmail("Example User", "test@example.com") 19 | content := mail.NewContent("text/html", "\n\n\t\n\n\nHello -name-,\n

\nI'm glad you are trying out the CustomArgs feature!\n

\nI hope you are having a great day in -city- :)\n

\n\n") 20 | m := mail.NewV3MailInit(from, subject, to, content) 21 | m.Personalizations[0].SetSubstitution("-name-", "Example User") 22 | m.Personalizations[0].SetSubstitution("-city-", "Denver") 23 | m.Personalizations[0].SetCustomArg("user_id", "343") 24 | m.Personalizations[0].SetCustomArg("batch_id", "3") 25 | 26 | m.SetCustomArg("campaign", "welcome") 27 | m.SetCustomArg("weekday", "morning") 28 | 29 | request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KEY"), "/v3/mail/send", "https://api.sendgrid.com") 30 | request.Method = "POST" 31 | request.Body = mail.GetRequestBody(m) 32 | response, err := sendgrid.API(request) 33 | if err != nil { 34 | log.Println(err) 35 | } else { 36 | fmt.Println(response.StatusCode) 37 | fmt.Println(response.Body) 38 | fmt.Println(response.Headers) 39 | } 40 | } 41 | ``` -------------------------------------------------------------------------------- /use-cases/substitutions-with-mailer-helper.md: -------------------------------------------------------------------------------- 1 | ## Substitutions - With Mail Helper Class 2 | 3 | ```go 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "log" 9 | "os" 10 | 11 | "github.com/sendgrid/sendgrid-go" 12 | "github.com/sendgrid/sendgrid-go/helpers/mail" 13 | ) 14 | 15 | func main() { 16 | from := mail.NewEmail("Example User", "test@example.com") 17 | subject := "Substitutions can be fun" 18 | to := mail.NewEmail("Example User", "test@example.com") 19 | content := mail.NewContent("text/html", "\n\n\t\n\n\nHello -name-,\n

\nI'm glad you are trying out the Substitutions feature!\n

\nI hope you are having a great day in -city- :)\n

\n\n") 20 | m := mail.NewV3MailInit(from, subject, to, content) 21 | m.Personalizations[0].SetSubstitution("-name-", "Example User") 22 | m.Personalizations[0].SetSubstitution("-city-", "Denver") 23 | m.Personalizations[0].SetSubstitution("-user_id-", "343") 24 | m.Personalizations[0].SetCustomArg("user_id", "-user_id-") 25 | m.Personalizations[0].SetCustomArg("city", "-city-") 26 | 27 | request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KEY"), "/v3/mail/send", "https://api.sendgrid.com") 28 | request.Method = "POST" 29 | request.Body = mail.GetRequestBody(m) 30 | response, err := sendgrid.API(request) 31 | if err != nil { 32 | log.Println(err) 33 | } else { 34 | fmt.Println(response.StatusCode) 35 | fmt.Println(response.Body) 36 | fmt.Println(response.Headers) 37 | } 38 | } 39 | ``` -------------------------------------------------------------------------------- /use-cases/sections-with-mailer-helper.md: -------------------------------------------------------------------------------- 1 | ## Sections - With Mail Helper Class 2 | 3 | ```go 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "log" 9 | "os" 10 | 11 | "github.com/sendgrid/sendgrid-go" 12 | "github.com/sendgrid/sendgrid-go/helpers/mail" 13 | ) 14 | 15 | func main() { 16 | from := mail.NewEmail("Example User", "test@example.com") 17 | subject := "Sections can be fun" 18 | to := mail.NewEmail("Example User", "test@example.com") 19 | content := mail.NewContent("text/html", "\n\n\t\n\n\n-wel-\n

\nI'm glad you are trying out the Sections feature!\n

\n-gday-\n

\n\n") 20 | m := mail.NewV3MailInit(from, subject, to, content) 21 | m.Personalizations[0].SetSubstitution("-name-", "Example User") 22 | m.Personalizations[0].SetSubstitution("-city-", "Denver") 23 | m.Personalizations[0].SetSubstitution("-wel-", "-welcome-") 24 | m.Personalizations[0].SetSubstitution("-gday-", "-great_day-") 25 | 26 | m.AddSection("-welcome-", "Hello -name-,") 27 | m.AddSection("-great_day-", "I hope you are having a great day in -city- :)") 28 | 29 | request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KEY"), "/v3/mail/send", "https://api.sendgrid.com") 30 | request.Method = "POST" 31 | request.Body = mail.GetRequestBody(m) 32 | response, err := sendgrid.API(request) 33 | if err != nil { 34 | log.Println(err) 35 | } else { 36 | fmt.Println(response.StatusCode) 37 | fmt.Println(response.Body) 38 | fmt.Println(response.Headers) 39 | } 40 | } 41 | ``` -------------------------------------------------------------------------------- /helpers/inbound/sample_data/default_data.txt: -------------------------------------------------------------------------------- 1 | --xYzZY 2 | Content-Disposition: form-data; name="headers" 3 | 4 | MIME-Version: 1.0 5 | Received: by 0.0.0.0 with HTTP; Wed, 10 Aug 2016 18:10:13 -0700 (PDT) 6 | From: Example User 7 | Date: Wed, 10 Aug 2016 18:10:13 -0700 8 | Subject: Inbound Parse Test Data 9 | To: inbound@inbound.example.com 10 | Content-Type: multipart/alternative; boundary=001a113df448cad2d00539c16e89 11 | 12 | --xYzZY 13 | Content-Disposition: form-data; name="dkim" 14 | 15 | {@sendgrid.com : pass} 16 | --xYzZY 17 | Content-Disposition: form-data; name="to" 18 | 19 | inbound@inbound.example.com 20 | --xYzZY 21 | Content-Disposition: form-data; name="html" 22 | 23 | Hello Twilio SendGrid! 24 | 25 | --xYzZY 26 | Content-Disposition: form-data; name="from" 27 | 28 | Example User 29 | --xYzZY 30 | Content-Disposition: form-data; name="text" 31 | 32 | Hello Twilio SendGrid! 33 | 34 | --xYzZY 35 | Content-Disposition: form-data; name="sender_ip" 36 | 37 | 0.0.0.0 38 | --xYzZY 39 | Content-Disposition: form-data; name="envelope" 40 | 41 | {"to":["inbound@inbound.example.com"],"from":"test@example.com"} 42 | --xYzZY 43 | Content-Disposition: form-data; name="attachments" 44 | 45 | 0 46 | --xYzZY 47 | Content-Disposition: form-data; name="subject" 48 | 49 | Testing non-raw 50 | --xYzZY 51 | Content-Disposition: form-data; name="charsets" 52 | 53 | {"to":"UTF-8","html":"UTF-8","subject":"UTF-8","from":"UTF-8","text":"UTF-8"} 54 | --xYzZY 55 | Content-Disposition: form-data; name="SPF" 56 | 57 | pass 58 | --xYzZY-- -------------------------------------------------------------------------------- /helpers/inbound/sample_data/raw_data.txt: -------------------------------------------------------------------------------- 1 | --xYzZY 2 | Content-Disposition: form-data; name="dkim" 3 | 4 | {@sendgrid.com : pass} 5 | --xYzZY 6 | Content-Disposition: form-data; name="email" 7 | 8 | MIME-Version: 1.0 9 | Received: by 0.0.0.0 with HTTP; Wed, 10 Aug 2016 14:44:21 -0700 (PDT) 10 | From: Example User 11 | Date: Wed, 10 Aug 2016 14:44:21 -0700 12 | Subject: Inbound Parse Test Raw Data 13 | To: inbound@inbound.inbound.com 14 | Content-Type: multipart/alternative; boundary=001a113ee97c89842f0539be8e7a 15 | 16 | --001a113ee97c89842f0539be8e7a 17 | Content-Type: text/plain; charset=UTF-8 18 | 19 | Hello Twilio SendGrid! 20 | 21 | --001a113ee97c89842f0539be8e7a 22 | Content-Type: text/html; charset=UTF-8 23 | Content-Transfer-Encoding: quoted-printable 24 | 25 | Hello Twilio SendGrid! 26 | 27 | --001a113ee97c89842f0539be8e7a-- 28 | 29 | --xYzZY 30 | Content-Disposition: form-data; name="to" 31 | 32 | inbound@inbound.inbound.com 33 | --xYzZY 34 | Content-Disposition: form-data; name="from" 35 | 36 | Example User 37 | --xYzZY 38 | Content-Disposition: form-data; name="sender_ip" 39 | 40 | 0.0.0.0 41 | --xYzZY 42 | Content-Disposition: form-data; name="envelope" 43 | 44 | {"to":["inbound@inbound.inbound.com"],"from":"test@example.com"} 45 | --xYzZY 46 | Content-Disposition: form-data; name="subject" 47 | 48 | Testing with Request.bin 49 | --xYzZY 50 | Content-Disposition: form-data; name="charsets" 51 | 52 | {"to":"UTF-8","subject":"UTF-8","from":"UTF-8"} 53 | --xYzZY 54 | Content-Disposition: form-data; name="SPF" 55 | 56 | pass 57 | --xYzZY-- -------------------------------------------------------------------------------- /use-cases/personalization-sending-single-email-single-recipient.md: -------------------------------------------------------------------------------- 1 | ### Personalization (with helper) - Sending a Single Email to a Single Recipient 2 | 3 | ```go 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "log" 9 | "os" 10 | 11 | "github.com/sendgrid/sendgrid-go" 12 | "github.com/sendgrid/sendgrid-go/helpers/mail" 13 | ) 14 | 15 | func main() { 16 | // create new *SGMailV3 17 | m := mail.NewV3Mail() 18 | 19 | from := mail.NewEmail("test", "test@example.com") 20 | content := mail.NewContent("text/html", "

%fname% : %CustomerID% - Personalizations are awesome!

") 21 | 22 | m.SetFrom(from) 23 | m.AddContent(content) 24 | 25 | // create new *Personalization 26 | personalization := mail.NewPersonalization() 27 | 28 | // populate `personalization` with data 29 | to := mail.NewEmail("Example User", "test1@example.com") 30 | 31 | personalization.AddTos(to) 32 | personalization.SetSubstitution("%fname%", "recipient") 33 | personalization.SetSubstitution("%CustomerID%", "CUSTOMER ID GOES HERE") 34 | personalization.Subject = "Having fun learning about personalizations?" 35 | 36 | // add `personalization` to `m` 37 | m.AddPersonalizations(personalization) 38 | 39 | request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KEY"), "/v3/mail/send", "https://api.sendgrid.com") 40 | request.Method = "POST" 41 | request.Body = mail.GetRequestBody(m) 42 | response, err := sendgrid.API(request) 43 | if err != nil { 44 | log.Println(err) 45 | } else { 46 | fmt.Println(response.StatusCode) 47 | fmt.Println(response.Body) 48 | fmt.Println(response.Headers) 49 | } 50 | } 51 | ``` -------------------------------------------------------------------------------- /use-cases/custom-args-without-mailer-helper.md: -------------------------------------------------------------------------------- 1 | ## CustomArgs - Without Mail Helper Class 2 | 3 | ```go 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "log" 9 | "os" 10 | 11 | "github.com/sendgrid/sendgrid-go" 12 | ) 13 | 14 | func main() { 15 | request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KEY"), "/v3/mail/send", "https://api.sendgrid.com") 16 | request.Method = "POST" 17 | request.Body = []byte(` { 18 | "personalizations": [ 19 | { 20 | "to": [ 21 | { 22 | "email": "test@example.com" 23 | } 24 | ], 25 | "subject": "CustomArgs can be fun", 26 | "substitutions": { 27 | "-name-": "Example User", 28 | "-city-": "Denver" 29 | }, 30 | "custom_args": { 31 | "user_id": "343", 32 | "batch_id": "3" 33 | } 34 | } 35 | ], 36 | "from": { 37 | "email": "test@example.com" 38 | }, 39 | "content": [ 40 | { 41 | "type": "text/html", 42 | "value": "\n\n\t\n\n\nHello -name-,\n

\nI'm glad you are trying out the CustomArgs feature!\n

\nI hope you are having a great day in -city- :)\n

\n\n" 43 | } 44 | ], 45 | "custom_args": { 46 | "campaign": "welcome", 47 | "weekday": "morning" 48 | } 49 | }`) 50 | response, err := sendgrid.API(request) 51 | if err != nil { 52 | log.Println(err) 53 | } else { 54 | fmt.Println(response.StatusCode) 55 | fmt.Println(response.Body) 56 | fmt.Println(response.Headers) 57 | } 58 | } 59 | ``` -------------------------------------------------------------------------------- /use-cases/substitutions-without-mailer-helper.md: -------------------------------------------------------------------------------- 1 | ## Substitutions - Without Mail Helper Class 2 | 3 | ```go 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "log" 9 | "os" 10 | 11 | "github.com/sendgrid/sendgrid-go" 12 | ) 13 | 14 | func main() { 15 | request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KEY"), "/v3/mail/send", "https://api.sendgrid.com") 16 | request.Method = "POST" 17 | request.Body = []byte(` { 18 | "personalizations": [ 19 | { 20 | "to": [ 21 | { 22 | "email": "test@example.com" 23 | } 24 | ], 25 | "subject": "Substitutions can be fun", 26 | "substitutions": { 27 | "-name-": "Example User", 28 | "-city-": "Denver", 29 | "-user_id-": "343" 30 | }, 31 | "custom_args": { 32 | "user_id": "-user_id-", 33 | "city": "-city-" 34 | } 35 | } 36 | ], 37 | "from": { 38 | "email": "test@example.com" 39 | }, 40 | "content": [ 41 | { 42 | "type": "text/html", 43 | "value": "\n\n\t\n\n\nHello -name-,\n

\nI'm glad you are trying out the Substitutions feature!\n

\nI hope you are having a great day in -city- :)\n

\n\n" 44 | } 45 | ] 46 | }`) 47 | response, err := sendgrid.API(request) 48 | if err != nil { 49 | log.Println(err) 50 | } else { 51 | fmt.Println(response.StatusCode) 52 | fmt.Println(response.Body) 53 | fmt.Println(response.Headers) 54 | } 55 | } 56 | ``` -------------------------------------------------------------------------------- /examples/eventwebhook/eventwebhook.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | 8 | "github.com/sendgrid/rest" 9 | "github.com/sendgrid/sendgrid-go" 10 | "github.com/sendgrid/sendgrid-go/helpers/eventwebhook" 11 | ) 12 | 13 | // EnableSignedWebhook : Enables Signed Event Webhook. 14 | // PATCH /user/webhooks/event/settings/signed 15 | func EnableSignedWebhook() { 16 | var err error 17 | apiKey := os.Getenv("SENDGRID_API_KEY") 18 | host := "https://api.sendgrid.com" 19 | request := sendgrid.GetRequest(apiKey, "/v3/user/webhooks/event/settings/signed", host) 20 | request.Method = rest.Patch 21 | s := eventwebhook.NewSettings() 22 | s.SetEnableSignedWebhook(true) 23 | request.Body, err = eventwebhook.GetRequestBody(s) 24 | if err != nil { 25 | log.Println(err) 26 | return 27 | } 28 | response, err := sendgrid.MakeRequest(request) 29 | if err != nil { 30 | log.Println(err) 31 | } else { 32 | fmt.Println(response.StatusCode) 33 | fmt.Println(response.Body) 34 | fmt.Println(response.Headers) 35 | } 36 | } 37 | 38 | // GetPublicKeyForSignedWebhook : Get Public Key for Event Webhook. 39 | // Get /user/webhooks/event/settings/signed 40 | func GetPublicKeyForSignedWebhook() { 41 | apiKey := os.Getenv("SENDGRID_API_KEY") 42 | host := "https://api.sendgrid.com" 43 | request := sendgrid.GetRequest(apiKey, "/v3/user/webhooks/event/settings/signed", host) 44 | request.Method = rest.Get 45 | response, err := sendgrid.MakeRequest(request) 46 | if err != nil { 47 | log.Println(err) 48 | } else { 49 | fmt.Println(response.StatusCode) 50 | fmt.Println(response.Body) 51 | fmt.Println(response.Headers) 52 | } 53 | } 54 | 55 | func main() { 56 | // add your function calls here 57 | } 58 | -------------------------------------------------------------------------------- /use-cases/twilio-setup.md: -------------------------------------------------------------------------------- 1 | ## 1. Obtain a Free Twilio Account 2 | 3 | Sign up for a free Twilio account [here](https://www.twilio.com/try-twilio?source=sendgrid-go). 4 | 5 | ## 2. Set Up Your Environment Variables 6 | 7 | The Twilio API allows for authentication using with either an API key/secret or your Account SID/Auth Token. You can create an API key [here](https://twil.io/get-api-key) or obtain your Account SID and Auth Token [here](https://twil.io/console). 8 | 9 | Once you have those, follow the steps below based on your operating system. 10 | 11 | ### Linux/Mac 12 | 13 | ```bash 14 | echo "export TWILIO_API_KEY='YOUR_TWILIO_API_KEY'" > twilio.env 15 | echo "export TWILIO_API_SECRET='YOUR_TWILIO_API_SECRET'" >> twilio.env 16 | 17 | # or 18 | 19 | echo "export TWILIO_ACCOUNT_SID='YOUR_TWILIO_ACCOUNT_SID'" > twilio.env 20 | echo "export TWILIO_AUTH_TOKEN='YOUR_TWILIO_AUTH_TOKEN'" >> twilio.env 21 | ``` 22 | 23 | Then: 24 | 25 | ```bash 26 | echo "twilio.env" >> .gitignore 27 | source ./twilio.env 28 | ``` 29 | 30 | ### Windows 31 | 32 | Temporarily set the environment variable (accessible only during the current CLI session): 33 | 34 | ```bash 35 | set TWILIO_API_KEY=YOUR_TWILIO_API_KEY 36 | set TWILIO_API_SECRET=YOUR_TWILIO_API_SECRET 37 | 38 | : or 39 | 40 | set TWILIO_ACCOUNT_SID=YOUR_TWILIO_ACCOUNT_SID 41 | set TWILIO_AUTH_TOKEN=YOUR_TWILIO_AUTH_TOKEN 42 | ``` 43 | 44 | Or permanently set the environment variable (accessible in all subsequent CLI sessions): 45 | 46 | ```bash 47 | setx TWILIO_API_KEY "YOUR_TWILIO_API_KEY" 48 | setx TWILIO_API_SECRET "YOUR_TWILIO_API_SECRET" 49 | 50 | : or 51 | 52 | setx TWILIO_ACCOUNT_SID "YOUR_TWILIO_ACCOUNT_SID" 53 | setx TWILIO_AUTH_TOKEN "YOUR_TWILIO_AUTH_TOKEN" 54 | ``` 55 | -------------------------------------------------------------------------------- /PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 16 | 17 | # Fixes # 18 | 19 | A short description of what this PR does. 20 | 21 | ### Checklist 22 | - [x] I acknowledge that all my contributions will be made under the project's license 23 | - [ ] I have made a material change to the repo (functionality, testing, spelling, grammar) 24 | - [ ] I have read the [Contribution Guidelines](https://github.com/sendgrid/sendgrid-go/blob/main/CONTRIBUTING.md) and my PR follows them 25 | - [ ] I have titled the PR appropriately 26 | - [ ] I have updated my branch with the main branch 27 | - [ ] I have added tests that prove my fix is effective or that my feature works 28 | - [ ] I have added the necessary documentation about the functionality in the appropriate .md file 29 | - [ ] I have added inline documentation to the code I modified 30 | 31 | If you have questions, please file a [support ticket](https://support.sendgrid.com). 32 | -------------------------------------------------------------------------------- /use-cases/sections-without-mailer-helper.md: -------------------------------------------------------------------------------- 1 | ## Sections - Without Mail Helper Class 2 | 3 | ```go 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "log" 9 | "os" 10 | 11 | "github.com/sendgrid/sendgrid-go" 12 | ) 13 | 14 | func main() { 15 | request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KEY"), "/v3/mail/send", "https://api.sendgrid.com") 16 | request.Method = "POST" 17 | request.Body = []byte(` { 18 | "personalizations": [ 19 | { 20 | "to": [ 21 | { 22 | "email": "test@example.com" 23 | } 24 | ], 25 | "subject": "Sections can be fun", 26 | "substitutions": { 27 | "-name-": "Example User", 28 | "-city-": "Denver", 29 | "-wel-": "-welcome-", 30 | "-gday-": "-great_day-" 31 | } 32 | } 33 | ], 34 | "from": { 35 | "email": "test@example.com" 36 | }, 37 | "content": [ 38 | { 39 | "type": "text/html", 40 | "value": "\n\n\t\n\n\n-wel-\n

\nI'm glad you are trying out the Sections feature!\n

\n-gday-\n

\n\n" 41 | } 42 | ], 43 | "sections": { 44 | "section": { 45 | "-welcome-": "Hello -name-,", 46 | "-great_day-": "I hope you are having a great day in -city- :)" 47 | } 48 | } 49 | }`) 50 | response, err := sendgrid.API(request) 51 | if err != nil { 52 | log.Println(err) 53 | } else { 54 | fmt.Println(response.StatusCode) 55 | fmt.Println(response.Body) 56 | fmt.Println(response.Headers) 57 | } 58 | } 59 | ``` -------------------------------------------------------------------------------- /use-cases/personalization-sending-single-email-single-recipient-with-cc.md: -------------------------------------------------------------------------------- 1 | 2 | ### Personalization (with helper) - Sending a Single Email to a Single Recipient with a CC 3 | 4 | ```go 5 | package main 6 | 7 | import ( 8 | "fmt" 9 | "log" 10 | "os" 11 | 12 | "github.com/sendgrid/sendgrid-go" 13 | "github.com/sendgrid/sendgrid-go/helpers/mail" 14 | ) 15 | 16 | func main() { 17 | // create new *SGMailV3 18 | m := mail.NewV3Mail() 19 | 20 | from := mail.NewEmail("test", "test@example.com") 21 | content := mail.NewContent("text/html", "

%fname% : %CustomerID% - Personalizations are awesome!

") 22 | 23 | m.SetFrom(from) 24 | m.AddContent(content) 25 | 26 | // create new *Personalization 27 | personalization := mail.NewPersonalization() 28 | 29 | // populate `personalization` with data 30 | to := mail.NewEmail("Example User", "test1@example.com") 31 | cc1 := mail.NewEmail("Example CC", "test2@example.com") 32 | 33 | personalization.AddTos(to) 34 | personalization.AddCCs(cc1) 35 | personalization.SetSubstitution("%fname%", "recipient") 36 | personalization.SetSubstitution("%CustomerID%", "CUSTOMER ID GOES HERE") 37 | personalization.Subject = "Having fun learning about personalizations?" 38 | 39 | // add `personalization` to `m` 40 | m.AddPersonalizations(personalization) 41 | 42 | request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KEY"), "/v3/mail/send", "https://api.sendgrid.com") 43 | request.Method = "POST" 44 | request.Body = mail.GetRequestBody(m) 45 | response, err := sendgrid.API(request) 46 | if err != nil { 47 | log.Println(err) 48 | } else { 49 | fmt.Println(response.StatusCode) 50 | fmt.Println(response.Body) 51 | fmt.Println(response.Headers) 52 | } 53 | } 54 | ``` -------------------------------------------------------------------------------- /use-cases/personalization-sending-single-email-to-multiple-recipients.md: -------------------------------------------------------------------------------- 1 | ### Personalization (with helper) - Sending a Single Email to Multiple Recipients 2 | 3 | ```go 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "log" 9 | "os" 10 | 11 | "github.com/sendgrid/sendgrid-go" 12 | "github.com/sendgrid/sendgrid-go/helpers/mail" 13 | ) 14 | 15 | func main() { 16 | // create new *SGMailV3 17 | m := mail.NewV3Mail() 18 | 19 | from := mail.NewEmail("test", "test@example.com") 20 | content := mail.NewContent("text/html", "

%fname% : %CustomerID% - Personalizations are awesome!

") 21 | 22 | m.SetFrom(from) 23 | m.AddContent(content) 24 | 25 | // create new *Personalization 26 | personalization := mail.NewPersonalization() 27 | 28 | // populate `personalization` with data 29 | to1 := mail.NewEmail("Example User 1", "test1@example.com") 30 | to2 := mail.NewEmail("Example User 2", "test2@example.com") 31 | to3 := mail.NewEmail("Example User 3", "test3@example.com") 32 | 33 | personalization.AddTos(to1, to2, to3) 34 | personalization.SetSubstitution("%fname%", "recipient") 35 | personalization.SetSubstitution("%CustomerID%", "CUSTOMER ID GOES HERE") 36 | personalization.Subject = "Having fun learning about personalizations?" 37 | 38 | // add `personalization` to `m` 39 | m.AddPersonalizations(personalization) 40 | 41 | request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KEY"), "/v3/mail/send", "https://api.sendgrid.com") 42 | request.Method = "POST" 43 | request.Body = mail.GetRequestBody(m) 44 | response, err := sendgrid.API(request) 45 | if err != nil { 46 | log.Println(err) 47 | } else { 48 | fmt.Println(response.StatusCode) 49 | fmt.Println(response.Body) 50 | fmt.Println(response.Headers) 51 | } 52 | } 53 | ``` -------------------------------------------------------------------------------- /examples/clients/clients.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | 8 | "github.com/sendgrid/sendgrid-go" 9 | ) 10 | 11 | // Retrieveemailstatisticsbyclienttype : Retrieve email statistics by client type. 12 | // GET /clients/stats 13 | func Retrieveemailstatisticsbyclienttype() { 14 | apiKey := os.Getenv("SENDGRID_API_KEY") 15 | host := "https://api.sendgrid.com" 16 | request := sendgrid.GetRequest(apiKey, "/v3/clients/stats", host) 17 | request.Method = "GET" 18 | queryParams := make(map[string]string) 19 | queryParams["aggregated_by"] = "day" 20 | queryParams["start_date"] = "2016-01-01" 21 | queryParams["end_date"] = "2016-04-01" 22 | request.QueryParams = queryParams 23 | response, err := sendgrid.API(request) 24 | if err != nil { 25 | log.Println(err) 26 | } else { 27 | fmt.Println(response.StatusCode) 28 | fmt.Println(response.Body) 29 | fmt.Println(response.Headers) 30 | } 31 | } 32 | 33 | // Retrievestatsbyaspecificclienttype : Retrieve stats by a specific client type. 34 | // GET /clients/{client_type}/stats 35 | func Retrievestatsbyaspecificclienttype() { 36 | apiKey := os.Getenv("SENDGRID_API_KEY") 37 | host := "https://api.sendgrid.com" 38 | request := sendgrid.GetRequest(apiKey, "/v3/clients/{client_type}/stats", host) 39 | request.Method = "GET" 40 | queryParams := make(map[string]string) 41 | queryParams["aggregated_by"] = "day" 42 | queryParams["start_date"] = "2016-01-01" 43 | queryParams["end_date"] = "2016-04-01" 44 | request.QueryParams = queryParams 45 | response, err := sendgrid.API(request) 46 | if err != nil { 47 | log.Println(err) 48 | } else { 49 | fmt.Println(response.StatusCode) 50 | fmt.Println(response.Body) 51 | fmt.Println(response.Headers) 52 | } 53 | } 54 | 55 | func main() { 56 | // add your function calls here 57 | } 58 | -------------------------------------------------------------------------------- /use-cases/personalization-sending-single-email-single-recipient-with-cc-bcc.md: -------------------------------------------------------------------------------- 1 | ### Personalization (with helper) - Sending a Single Email to a Single Recipient with a CC and a BCC 2 | 3 | ```go 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "log" 9 | "os" 10 | 11 | "github.com/sendgrid/sendgrid-go" 12 | "github.com/sendgrid/sendgrid-go/helpers/mail" 13 | ) 14 | 15 | func main() { 16 | // create new *SGMailV3 17 | m := mail.NewV3Mail() 18 | 19 | from := mail.NewEmail("test", "test@example.com") 20 | content := mail.NewContent("text/html", "

%fname% : %CustomerID% - Personalizations are awesome!

") 21 | 22 | m.SetFrom(from) 23 | m.AddContent(content) 24 | 25 | // create new *Personalization 26 | personalization := mail.NewPersonalization() 27 | 28 | // populate `personalization` with data 29 | to := mail.NewEmail("Example User", "test1@example.com") 30 | cc1 := mail.NewEmail("Example CC", "test2@example.com") 31 | bcc1 := mail.NewEmail("Example BCC", "test3@example.com") 32 | 33 | personalization.AddTos(to) 34 | personalization.AddCCs(cc1) 35 | personalization.AddBCCs(bcc1) 36 | personalization.SetSubstitution("%fname%", "recipient") 37 | personalization.SetSubstitution("%CustomerID%", "CUSTOMER ID GOES HERE") 38 | personalization.Subject = "Having fun learning about personalizations?" 39 | 40 | // add `personalization` to `m` 41 | m.AddPersonalizations(personalization) 42 | 43 | request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KEY"), "/v3/mail/send", "https://api.sendgrid.com") 44 | request.Method = "POST" 45 | request.Body = mail.GetRequestBody(m) 46 | response, err := sendgrid.API(request) 47 | if err != nil { 48 | log.Println(err) 49 | } else { 50 | fmt.Println(response.StatusCode) 51 | fmt.Println(response.Body) 52 | fmt.Println(response.Headers) 53 | } 54 | } 55 | ``` 56 | -------------------------------------------------------------------------------- /use-cases/attachments-without-mailer-helper.md: -------------------------------------------------------------------------------- 1 | ## Attachments - Without Mail Helper Class 2 | 3 | ```go 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "log" 9 | "os" 10 | 11 | "github.com/sendgrid/sendgrid-go" 12 | ) 13 | 14 | func main() { 15 | request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KEY"), "/v3/mail/send", "https://api.sendgrid.com") 16 | request.Method = "POST" 17 | request.Body = []byte(` { 18 | "personalizations": [ 19 | { 20 | "to": [ 21 | { 22 | "email": "test1@example.com" 23 | } 24 | ], 25 | "subject": "Attachments - Demystified!" 26 | } 27 | } 28 | ], 29 | "from": { 30 | "email": "test@example.com" 31 | }, 32 | "content": [ 33 | { 34 | "type": "text/html", 35 | "value": "

Sending different attachments.

" 36 | } 37 | ], 38 | "attachments": [ 39 | { 40 | "content": "SGVsbG8gV29ybGQh", 41 | "disposition": "attachment", 42 | "filename": "testing.txt", 43 | "type": "txt" 44 | }, 45 | { 46 | "content": "BASE64 encoded content block here", 47 | "disposition": "inline", 48 | "content_id": "testing_2", 49 | "filename": "testing.jpg", 50 | "type": "jpg" 51 | }, 52 | { 53 | "content": "BASE64 encoded content block here", 54 | "disposition": "attachment", 55 | "filename": "testing.pdf", 56 | "type": "pdf" 57 | } 58 | ] 59 | }`) 60 | response, err := sendgrid.API(request) 61 | if err != nil { 62 | log.Println(err) 63 | } else { 64 | fmt.Println(response.StatusCode) 65 | fmt.Println(response.Body) 66 | fmt.Println(response.Headers) 67 | } 68 | } 69 | ``` 70 | -------------------------------------------------------------------------------- /use-cases/personalization-sending-single-email-to-single-recipients-with-multiple-cc-bcc.md: -------------------------------------------------------------------------------- 1 | ### Personalization (with helper) - Sending a Single Email to a Single Recipient with Multiple CCs/BCCs 2 | 3 | ```go 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "log" 9 | "os" 10 | 11 | "github.com/sendgrid/sendgrid-go" 12 | "github.com/sendgrid/sendgrid-go/helpers/mail" 13 | ) 14 | 15 | func main() { 16 | // create new *SGMailV3 17 | m := mail.NewV3Mail() 18 | 19 | from := mail.NewEmail("test", "test@example.com") 20 | content := mail.NewContent("text/html", "

%fname% : %CustomerID% - Personalizations are awesome!

") 21 | 22 | m.SetFrom(from) 23 | m.AddContent(content) 24 | 25 | // create new *Personalization 26 | personalization := mail.NewPersonalization() 27 | 28 | // populate `personalization` with data 29 | to := mail.NewEmail("Example User 1", "test1@example.com") 30 | cc1 := mail.NewEmail("Example User 2", "test2@example.com") 31 | cc2 := mail.NewEmail("Example User 3", "test3@example.com") 32 | cc3 := mail.NewEmail("Example User 3", "test4@example.com") 33 | 34 | personalization.AddTos(to) 35 | personalization.AddCCs(cc1, cc2, cc3) 36 | personalization.SetSubstitution("%fname%", "recipient") 37 | personalization.SetSubstitution("%CustomerID%", "CUSTOMER ID GOES HERE") 38 | personalization.Subject = "Having fun learning about personalizations?" 39 | 40 | // add `personalization` to `m` 41 | m.AddPersonalizations(personalization) 42 | 43 | request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KEY"), "/v3/mail/send", "https://api.sendgrid.com") 44 | request.Method = "POST" 45 | request.Body = mail.GetRequestBody(m) 46 | response, err := sendgrid.API(request) 47 | if err != nil { 48 | log.Println(err) 49 | } else { 50 | fmt.Println(response.StatusCode) 51 | fmt.Println(response.Body) 52 | fmt.Println(response.Headers) 53 | } 54 | } 55 | ``` -------------------------------------------------------------------------------- /use-cases/personalization-without-helper-sending-two-emails-to-two-groups-recipients.md: -------------------------------------------------------------------------------- 1 | ### Personalization (without helper) - Sending Two Different Emails to Two Different Groups of Recipients 2 | 3 | ```go 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "log" 9 | "os" 10 | 11 | "github.com/sendgrid/sendgrid-go" 12 | ) 13 | 14 | func main() { 15 | request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KEY"), "/v3/mail/send", "https://api.sendgrid.com") 16 | request.Method = "POST" 17 | request.Body = []byte(`{ 18 | "personalizations": [{ 19 | "to": [{ 20 | "email": "recipient1@example.com" 21 | }], 22 | "cc": [{ 23 | "email": "recipient2@example.com" 24 | }, { 25 | "email": "recipient3@example.com" 26 | }, { 27 | "email": "recipient4@example.com" 28 | }], 29 | "substitutions": { 30 | "%fname%": "recipient", 31 | "%CustomerID%": "CUSTOMER ID GOES HERE" 32 | }, 33 | "subject": "YOUR SUBJECT LINE GOES HERE" 34 | }, { 35 | "to": [{ 36 | "email": "recipient5@example.com" 37 | }], 38 | "cc": [{ 39 | "email": "recipient6@example.com" 40 | }, { 41 | "email": "recipient7@example.com" 42 | }, { 43 | "email": "recipient8@example.com" 44 | }], 45 | "substitutions": { 46 | "%fname%": "recipient2", 47 | "%CustomerID%": 55 48 | }, 49 | "subject": "YOUR SUBJECT LINE GOES HERE" 50 | }], 51 | "from": { 52 | "email": "test@example.com" 53 | }, 54 | "content": [ 55 | { 56 | "type": "text/html", 57 | "value": "

%fname% : %CustomerID% - Personalizations are awesome!

" 58 | } 59 | ] 60 | }`) 61 | response, err := sendgrid.API(request) 62 | if err != nil { 63 | log.Println(err) 64 | } else { 65 | fmt.Println(response.StatusCode) 66 | fmt.Println(response.Body) 67 | fmt.Println(response.Headers) 68 | } 69 | } 70 | ``` -------------------------------------------------------------------------------- /use-cases/personalization-sending-two-emails-to-two-groups-recipients-from-two-different-from-emails.md: -------------------------------------------------------------------------------- 1 | 2 | ### Personalization (with helper) - Sending Two Different Emails to Two Different Groups of Recipients from two different From emails 3 | 4 | ```go 5 | package main 6 | 7 | import ( 8 | "fmt" 9 | "log" 10 | "os" 11 | 12 | "github.com/sendgrid/sendgrid-go" 13 | "github.com/sendgrid/sendgrid-go/helpers/mail" 14 | ) 15 | 16 | func main() { 17 | // create new *SGMailV3 18 | m := mail.NewV3Mail() 19 | 20 | from := mail.NewEmail("Example Sender 1", "defaultSender@example.com") 21 | content := mail.NewContent("text/html", "

Personalizations are awesome!

") 22 | 23 | m.SetFrom(from) 24 | m.AddContent(content) 25 | 26 | // create new *Personalization(s) 27 | personalization1 := mail.NewPersonalization() 28 | personalization2 := mail.NewPersonalization() 29 | 30 | // populate `personalization1` with data 31 | //this email will be sent from Example Sender 1 32 | p1_to := mail.NewEmail("Example User 1", "test1@example.com") 33 | 34 | personalization1.AddTos(p1_to) 35 | personalization1.Subject = "Having fun learning about personalizations?" 36 | 37 | // populate `personalization2` with data 38 | //this email will be sent from Example Sender 2 39 | p2_from :=mail.NewEmail("Example Sender 2", "sender2@example.com") 40 | p2_to := mail.NewEmail("Example User 1", "test1@example.com") 41 | 42 | personalization2.AddFrom(p2_from) 43 | personalization2.AddTos(p2_to) 44 | personalization2.Subject = "Personalizations are fun!" 45 | 46 | // add `personalization1` and `personalization2` to `m` 47 | m.AddPersonalizations(personalization1, personalization2) 48 | 49 | request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KEY"), "/v3/mail/send", "https://api.sendgrid.com") 50 | request.Method = "POST" 51 | request.Body = mail.GetRequestBody(m) 52 | response, err := sendgrid.API(request) 53 | if err != nil { 54 | log.Println(err) 55 | } else { 56 | fmt.Println(response.StatusCode) 57 | fmt.Println(response.Body) 58 | fmt.Println(response.Headers) 59 | } 60 | } 61 | ``` -------------------------------------------------------------------------------- /examples/partnersettings/partnersettings.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | 8 | "github.com/sendgrid/sendgrid-go" 9 | ) 10 | 11 | // Returnsalistofallpartnersettings : Returns a list of all partner settings. 12 | // GET /partner_settings 13 | func Returnsalistofallpartnersettings() { 14 | apiKey := os.Getenv("SENDGRID_API_KEY") 15 | host := "https://api.sendgrid.com" 16 | request := sendgrid.GetRequest(apiKey, "/v3/partner_settings", host) 17 | request.Method = "GET" 18 | queryParams := make(map[string]string) 19 | queryParams["limit"] = "1" 20 | queryParams["offset"] = "1" 21 | request.QueryParams = queryParams 22 | response, err := sendgrid.API(request) 23 | if err != nil { 24 | log.Println(err) 25 | } else { 26 | fmt.Println(response.StatusCode) 27 | fmt.Println(response.Body) 28 | fmt.Println(response.Headers) 29 | } 30 | } 31 | 32 | // UpdatesNewRelicpartnersettings : Updates New Relic partner settings. 33 | // PATCH /partner_settings/new_relic 34 | func UpdatesNewRelicpartnersettings() { 35 | apiKey := os.Getenv("SENDGRID_API_KEY") 36 | host := "https://api.sendgrid.com" 37 | request := sendgrid.GetRequest(apiKey, "/v3/partner_settings/new_relic", host) 38 | request.Method = "PATCH" 39 | request.Body = []byte(` { 40 | "enable_subuser_statistics": true, 41 | "enabled": true, 42 | "license_key": "" 43 | }`) 44 | response, err := sendgrid.API(request) 45 | if err != nil { 46 | log.Println(err) 47 | } else { 48 | fmt.Println(response.StatusCode) 49 | fmt.Println(response.Body) 50 | fmt.Println(response.Headers) 51 | } 52 | } 53 | 54 | // ReturnsallNewRelicpartnersettings : Returns all New Relic partner settings. 55 | // GET /partner_settings/new_relic 56 | func ReturnsallNewRelicpartnersettings() { 57 | apiKey := os.Getenv("SENDGRID_API_KEY") 58 | host := "https://api.sendgrid.com" 59 | request := sendgrid.GetRequest(apiKey, "/v3/partner_settings/new_relic", host) 60 | request.Method = "GET" 61 | response, err := sendgrid.API(request) 62 | if err != nil { 63 | log.Println(err) 64 | } else { 65 | fmt.Println(response.StatusCode) 66 | fmt.Println(response.Body) 67 | fmt.Println(response.Headers) 68 | } 69 | } 70 | 71 | func main() { 72 | // add your function calls here 73 | } 74 | -------------------------------------------------------------------------------- /helpers/eventwebhook/eventwebhook.go: -------------------------------------------------------------------------------- 1 | package eventwebhook 2 | 3 | import ( 4 | "crypto/ecdsa" 5 | "crypto/sha256" 6 | "crypto/x509" 7 | "encoding/asn1" 8 | "encoding/base64" 9 | "encoding/json" 10 | "math/big" 11 | ) 12 | 13 | const ( 14 | // VerificationHTTPHeader is the signature verification http header name for the signature being sent 15 | VerificationHTTPHeader = "X-Twilio-Email-Event-Webhook-Signature" 16 | // TimestampHTTPHeader is the timestamp http header name for timestamp 17 | TimestampHTTPHeader = "X-Twilio-Email-Event-Webhook-Timestamp" 18 | ) 19 | 20 | // Settings ... 21 | type Settings struct { 22 | EnableSignedWebhook *bool `json:"enabled,omitempty"` 23 | } 24 | 25 | // RS represents the ECDSA signature 26 | type RS struct { 27 | R *big.Int 28 | S *big.Int 29 | } 30 | 31 | // NewSettings ... 32 | func NewSettings() *Settings { 33 | return &Settings{} 34 | } 35 | 36 | // SetEnableSignedWebhook ... 37 | func (s *Settings) SetEnableSignedWebhook(enable bool) { 38 | s.EnableSignedWebhook = &enable 39 | } 40 | 41 | // GetRequestBody ... 42 | func GetRequestBody(s *Settings) ([]byte, error) { 43 | b, err := json.Marshal(s) 44 | if err != nil { 45 | return nil, err 46 | } 47 | return b, nil 48 | } 49 | 50 | // ConvertPublicKeyBase64ToECDSA takes a base64 ECDSA public key and converts it into the ECDSA Public Key type 51 | func ConvertPublicKeyBase64ToECDSA(base64PublicKey string) (*ecdsa.PublicKey, error) { 52 | pk, err := base64.StdEncoding.DecodeString(base64PublicKey) 53 | if err != nil { 54 | return nil, err 55 | } 56 | 57 | publicKey, err := x509.ParsePKIXPublicKey(pk) 58 | if err != nil { 59 | return nil, err 60 | } 61 | 62 | return publicKey.(*ecdsa.PublicKey), nil 63 | } 64 | 65 | // VerifySignature uses the ECDSA publicKey and verifies received payload and signature 66 | func VerifySignature(publicKey *ecdsa.PublicKey, payload []byte, signature, timestamp string) (bool, error) { 67 | signatureBytes, err := base64.StdEncoding.DecodeString(signature) 68 | if err != nil { 69 | return false, err 70 | } 71 | 72 | ecdsaSig := &RS{} 73 | _, err = asn1.Unmarshal(signatureBytes, ecdsaSig) 74 | if err != nil { 75 | return false, err 76 | } 77 | 78 | hash := sha256.New() 79 | hash.Write([]byte(timestamp)) 80 | hash.Write(payload) 81 | 82 | return ecdsa.Verify(publicKey, hash.Sum(nil), ecdsaSig.R, ecdsaSig.S), nil 83 | } 84 | -------------------------------------------------------------------------------- /use-cases/transactional-templates-without-mailer-helper.md: -------------------------------------------------------------------------------- 1 | ## Transaction Templates - Without Mail Helper Class 2 | 3 | ```go 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "github.com/sendgrid/sendgrid-go" 9 | "github.com/sendgrid/sendgrid-go/helpers/mail" 10 | "os" 11 | ) 12 | 13 | func main() { 14 | request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KEY"), "/v3/mail/send", "https://api.sendgrid.com") 15 | request.Method = "POST" 16 | request.Body = []byte(` { 17 | "from": { 18 | "email": "test@example.com" 19 | }, 20 | "personalizations": [ 21 | { 22 | "to": [ 23 | { 24 | "email": "test@example.com" 25 | } 26 | ], 27 | "dynamic_template_data":{ 28 | "total":"$ 239.85", 29 | "items":[ 30 | { 31 | "text":"New Line Sneakers", 32 | "image":"https://marketing-image-production.s3.amazonaws.com/uploads/8dda1131320a6d978b515cc04ed479df259a458d5d45d58b6b381cae0bf9588113e80ef912f69e8c4cc1ef1a0297e8eefdb7b270064cc046b79a44e21b811802.png", 33 | "price":"$ 79.95" 34 | }, 35 | { 36 | "text":"Old Line Sneakers", 37 | "image":"https://marketing-image-production.s3.amazonaws.com/uploads/3629f54390ead663d4eb7c53702e492de63299d7c5f7239efdc693b09b9b28c82c924225dcd8dcb65732d5ca7b7b753c5f17e056405bbd4596e4e63a96ae5018.png", 38 | "price":"$ 79.95" 39 | }, 40 | { 41 | "text":"Blue Line Sneakers", 42 | "image":"https://marketing-image-production.s3.amazonaws.com/uploads/00731ed18eff0ad5da890d876c456c3124a4e44cb48196533e9b95fb2b959b7194c2dc7637b788341d1ff4f88d1dc88e23f7e3704726d313c57f350911dd2bd0.png", 43 | "price":"$ 79.95" 44 | } 45 | ], 46 | "receipt":true, 47 | "name":"Sample Name", 48 | "address01":"1234 Fake St.", 49 | "address02":"Apt. 123", 50 | "city":"Place", 51 | "state":"CO", 52 | "zip":"80202" 53 | } 54 | } 55 | ], 56 | "template_id":"d-c6dcf1f72bdd4beeb15a9aa6c72fcd2c" 57 | }`) 58 | response, err := sendgrid.API(request) 59 | if err != nil { 60 | log.Println(err) 61 | } else { 62 | fmt.Println(response.StatusCode) 63 | fmt.Println(response.Body) 64 | fmt.Println(response.Headers) 65 | } 66 | } 67 | ``` -------------------------------------------------------------------------------- /use-cases/personalization-sending-two-emails-to-two-groups-recipients.md: -------------------------------------------------------------------------------- 1 | 2 | ### Personalization (with helper) - Sending Two Different Emails to Two Different Groups of Recipients 3 | 4 | ```go 5 | package main 6 | 7 | import ( 8 | "fmt" 9 | "log" 10 | "os" 11 | 12 | "github.com/sendgrid/sendgrid-go" 13 | "github.com/sendgrid/sendgrid-go/helpers/mail" 14 | ) 15 | 16 | func main() { 17 | // create new *SGMailV3 18 | m := mail.NewV3Mail() 19 | 20 | from := mail.NewEmail("test", "test@example.com") 21 | content := mail.NewContent("text/html", "

%fname% : %CustomerID% - Personalizations are awesome!

") 22 | 23 | m.SetFrom(from) 24 | m.AddContent(content) 25 | 26 | // create new *Personalization(s) 27 | personalization1 := mail.NewPersonalization() 28 | personalization2 := mail.NewPersonalization() 29 | 30 | // populate `personalization1` with data 31 | p1_to := mail.NewEmail("Example User 1", "test1@example.com") 32 | p1_cc1 := mail.NewEmail("Example User 2", "test2@example.com") 33 | p1_cc2 := mail.NewEmail("Example User 3", "test3@example.com") 34 | p1_cc3 := mail.NewEmail("Example User 3", "test4@example.com") 35 | 36 | personalization1.AddTos(p1_to) 37 | personalization1.AddCCs(p1_cc1, p1_cc2, p1_cc3) 38 | personalization1.SetSubstitution("%fname%", "recipient") 39 | personalization1.SetSubstitution("%CustomerID%", "CUSTOMER ID GOES HERE") 40 | personalization1.Subject = "Having fun learning about personalizations?" 41 | 42 | // populate `personalization2` with data 43 | p2_to := mail.NewEmail("Example User 1", "test1@example.com") 44 | p2_cc1 := mail.NewEmail("Example User 2", "test2@example.com") 45 | p2_cc2 := mail.NewEmail("Example User 3", "test3@example.com") 46 | p2_cc3 := mail.NewEmail("Example User 3", "test4@example.com") 47 | 48 | personalization2.AddTos(p2_to) 49 | personalization2.AddCCs(p2_cc1, p2_cc2, p2_cc3) 50 | personalization2.SetSubstitution("%fname%", "recipient2") 51 | personalization2.SetSubstitution("%CustomerID%", "55") 52 | personalization2.Subject = "Personalizations are fun!" 53 | 54 | // add `personalization1` and `personalization2` to `m` 55 | m.AddPersonalizations(personalization1, personalization2) 56 | 57 | request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KEY"), "/v3/mail/send", "https://api.sendgrid.com") 58 | request.Method = "POST" 59 | request.Body = mail.GetRequestBody(m) 60 | response, err := sendgrid.API(request) 61 | if err != nil { 62 | log.Println(err) 63 | } else { 64 | fmt.Println(response.StatusCode) 65 | fmt.Println(response.Body) 66 | fmt.Println(response.Headers) 67 | } 68 | } 69 | ``` -------------------------------------------------------------------------------- /use-cases/attachments-with-mailer-helper.md: -------------------------------------------------------------------------------- 1 | ## Attachments - With Mail Helper Class 2 | 3 | ```go 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "log" 9 | "os" 10 | "encoding/base64" 11 | "io/ioutil" 12 | "github.com/sendgrid/sendgrid-go" 13 | "github.com/sendgrid/sendgrid-go/helpers/mail" 14 | ) 15 | 16 | func main() { 17 | // create new *SGMailV3 18 | m := mail.NewV3Mail() 19 | 20 | from := mail.NewEmail("test", "test@example.com") 21 | content := mail.NewContent("text/html", "

Sending different attachments.

") 22 | to := mail.NewEmail("Example User", "test1@example.com") 23 | 24 | m.SetFrom(from) 25 | m.AddContent(content) 26 | 27 | // create new *Personalization 28 | personalization := mail.NewPersonalization() 29 | personalization.AddTos(to) 30 | personalization.Subject = "Attachments - Demystified!" 31 | 32 | // add `personalization` to `m` 33 | m.AddPersonalizations(personalization) 34 | 35 | // read/attach .txt file 36 | a_txt := mail.NewAttachment() 37 | dat, err := io.ReadFile("testing.txt") 38 | if err != nil { 39 | fmt.Println(err) 40 | } 41 | encoded := base64.StdEncoding.EncodeToString([]byte(dat)) 42 | a_txt.SetContent(encoded) 43 | a_txt.SetType("text/plain") 44 | a_txt.SetFilename("testing.txt") 45 | a_txt.SetDisposition("attachment") 46 | 47 | // read/attach .pdf file 48 | a_pdf := mail.NewAttachment() 49 | dat, err = io.ReadFile("testing.pdf") 50 | if err != nil { 51 | fmt.Println(err) 52 | } 53 | encoded = base64.StdEncoding.EncodeToString([]byte(dat)) 54 | a_pdf.SetContent(encoded) 55 | a_pdf.SetType("application/pdf") 56 | a_pdf.SetFilename("testing.pdf") 57 | a_pdf.SetDisposition("attachment") 58 | 59 | // read/attach inline .jpg file 60 | a_jpg := mail.NewAttachment() 61 | dat, err = io.ReadFile("testing.jpg") 62 | if err != nil { 63 | fmt.Println(err) 64 | } 65 | encoded = base64.StdEncoding.EncodeToString([]byte(dat)) 66 | a_jpg.SetContent(encoded) 67 | a_jpg.SetType("image/jpeg") 68 | a_jpg.SetFilename("testing.jpg") 69 | a_jpg.SetDisposition("inline") 70 | a_jpg.SetContentID("Test Attachment") 71 | 72 | // add `a_txt`, `a_pdf` and `a_jpg` to `m` 73 | m.AddAttachment(a_txt) 74 | m.AddAttachment(a_pdf) 75 | m.AddAttachment(a_jpg) 76 | 77 | request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KEY"), "/v3/mail/send", "https://api.sendgrid.com") 78 | request.Method = "POST" 79 | request.Body = mail.GetRequestBody(m) 80 | response, err := sendgrid.API(request) 81 | if err != nil { 82 | log.Println(err) 83 | } else { 84 | fmt.Println(response.StatusCode) 85 | fmt.Println(response.Body) 86 | fmt.Println(response.Headers) 87 | } 88 | } 89 | ``` 90 | -------------------------------------------------------------------------------- /examples/emailactivity/emailactivity.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/url" 7 | "os" 8 | 9 | "github.com/sendgrid/sendgrid-go" 10 | ) 11 | 12 | // GetMessages : Filter all messages 13 | // GET /messages 14 | func GetMessages() { 15 | apiKey := os.Getenv("YOUR_SENDGRID_APIKEY") 16 | host := "https://api.sendgrid.com" 17 | request := sendgrid.GetRequest(apiKey, "/v3/messages", host) 18 | request.Method = "GET" 19 | 20 | filterKey := "to_email" 21 | filterOperator := url.QueryEscape("=") 22 | filterValue := "testing@sendgrid.net" 23 | filterValue = url.QueryEscape(fmt.Sprintf("\"%s\"", filterValue)) 24 | 25 | queryParams := make(map[string]string) 26 | queryParams["query"] = fmt.Sprintf("%s%s%s", filterKey, filterOperator, filterValue) 27 | queryParams["limit"] = "1" 28 | request.QueryParams = queryParams 29 | 30 | response, err := sendgrid.API(request) 31 | if err != nil { 32 | log.Println(err) 33 | } else { 34 | fmt.Println(response.StatusCode) 35 | fmt.Println(response.Body) 36 | fmt.Println(response.Headers) 37 | } 38 | } 39 | 40 | // GetMessagesByID : Filter messages by message ID 41 | // GET /messages/{msg_id} 42 | func GetMessagesByID() { 43 | apiKey := os.Getenv("YOUR_SENDGRID_APIKEY") 44 | host := "https://api.sendgrid.com" 45 | request := sendgrid.GetRequest(apiKey, "/v3/messages/{msg_id}", host) 46 | request.Method = "GET" 47 | response, err := sendgrid.API(request) 48 | if err != nil { 49 | log.Println(err) 50 | } else { 51 | fmt.Println(response.StatusCode) 52 | fmt.Println(response.Body) 53 | fmt.Println(response.Headers) 54 | } 55 | } 56 | 57 | // RequestCSV : Request a CSV 58 | // POST /messages/download 59 | func RequestCSV() { 60 | apiKey := os.Getenv("YOUR_SENDGRID_APIKEY") 61 | host := "https://api.sendgrid.com" 62 | request := sendgrid.GetRequest(apiKey, "/v3/messages/download", host) 63 | request.Method = "POST" 64 | response, err := sendgrid.API(request) 65 | if err != nil { 66 | log.Println(err) 67 | } else { 68 | fmt.Println(response.StatusCode) 69 | fmt.Println(response.Body) 70 | fmt.Println(response.Headers) 71 | } 72 | } 73 | 74 | // DownloadCSV : Download CSV 75 | // GET /messages/download/{download_uuid} 76 | func DownloadCSV() { 77 | apiKey := os.Getenv("YOUR_SENDGRID_APIKEY") 78 | host := "https://api.sendgrid.com" 79 | request := sendgrid.GetRequest(apiKey, "/v3/messages/download/{download_uuid}", host) 80 | request.Method = "GET" 81 | response, err := sendgrid.API(request) 82 | if err != nil { 83 | log.Println(err) 84 | } else { 85 | fmt.Println(response.StatusCode) 86 | fmt.Println(response.Body) 87 | fmt.Println(response.Headers) 88 | } 89 | } 90 | 91 | func main() { 92 | // add your function calls here 93 | } 94 | -------------------------------------------------------------------------------- /use-cases/transactional-templates-with-mailer-helper.md: -------------------------------------------------------------------------------- 1 | ## Transactional Templates - With Mail Helper Class 2 | 3 | ```go 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "github.com/sendgrid/sendgrid-go" 9 | "github.com/sendgrid/sendgrid-go/helpers/mail" 10 | "os" 11 | ) 12 | 13 | func main() { 14 | m := mail.NewV3Mail() 15 | 16 | address := "test@example.com" 17 | name := "Example User" 18 | e := mail.NewEmail(name, address) 19 | m.SetFrom(e) 20 | 21 | m.SetTemplateID("d-c6dcf1f72bdd4beeb15a9aa6c72fcd2c") 22 | 23 | p := mail.NewPersonalization() 24 | tos := []*mail.Email{ 25 | mail.NewEmail("Example User", "test1@example.com"), 26 | } 27 | p.AddTos(tos...) 28 | 29 | p.SetDynamicTemplateData("receipt", "true") 30 | p.SetDynamicTemplateData("total", "$ 239.85") 31 | 32 | items := []struct { 33 | text string 34 | image string 35 | price string 36 | }{ 37 | {"New Line Sneakers", "https://marketing-image-production.s3.amazonaws.com/uploads/8dda1131320a6d978b515cc04ed479df259a458d5d45d58b6b381cae0bf9588113e80ef912f69e8c4cc1ef1a0297e8eefdb7b270064cc046b79a44e21b811802.png", "$ 79.95"}, 38 | {"Old Line Sneakers", "https://marketing-image-production.s3.amazonaws.com/uploads/3629f54390ead663d4eb7c53702e492de63299d7c5f7239efdc693b09b9b28c82c924225dcd8dcb65732d5ca7b7b753c5f17e056405bbd4596e4e63a96ae5018.png", "$ 79.95"}, 39 | {"Blue Line Sneakers", "https://marketing-image-production.s3.amazonaws.com/uploads/00731ed18eff0ad5da890d876c456c3124a4e44cb48196533e9b95fb2b959b7194c2dc7637b788341d1ff4f88d1dc88e23f7e3704726d313c57f350911dd2bd0.png", "$ 79.95"}, 40 | } 41 | 42 | var itemList []map[string]string 43 | var item map[string]string 44 | for _, v := range items { 45 | item = make(map[string]string) 46 | item["text"] = v.text 47 | item["image"] = v.image 48 | item["price"] = v.price 49 | itemList = append(itemList, item) 50 | } 51 | p.SetDynamicTemplateData("items", itemList) 52 | 53 | p.SetDynamicTemplateData("name", "Sample Name") 54 | p.SetDynamicTemplateData("address01", "1234 Fake St.") 55 | p.SetDynamicTemplateData("address02", "Apt. 123") 56 | p.SetDynamicTemplateData("city", "Place") 57 | p.SetDynamicTemplateData("state", "CO") 58 | p.SetDynamicTemplateData("zip", "80202") 59 | 60 | m.AddPersonalizations(p) 61 | 62 | request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KEY"), "/v3/mail/send", "https://api.sendgrid.com") 63 | request.Method = "POST" 64 | var Body = mail.GetRequestBody(m) 65 | request.Body = Body 66 | response, err := sendgrid.API(request) 67 | if err != nil { 68 | fmt.Println(err) 69 | } else { 70 | fmt.Println(response.StatusCode) 71 | fmt.Println(response.Body) 72 | fmt.Println(response.Headers) 73 | } 74 | } 75 | ``` 76 | -------------------------------------------------------------------------------- /sendgrid.go: -------------------------------------------------------------------------------- 1 | package sendgrid 2 | 3 | import ( 4 | "errors" 5 | "github.com/sendgrid/rest" 6 | "net/url" 7 | ) 8 | 9 | // sendGridOptions for CreateRequest 10 | type sendGridOptions struct { 11 | Key string 12 | Endpoint string 13 | Host string 14 | Subuser string 15 | } 16 | 17 | // sendgrid host map for different regions 18 | var allowedRegionsHostMap = map[string]string{ 19 | "eu": "https://api.eu.sendgrid.com", 20 | "global": "https://api.sendgrid.com", 21 | } 22 | 23 | // GetRequest 24 | // @return [Request] a default request object 25 | func GetRequest(key, endpoint, host string) rest.Request { 26 | return createSendGridRequest(sendGridOptions{key, endpoint, host, ""}) 27 | } 28 | 29 | // GetRequestSubuser like GetRequest but with On-Behalf of Subuser 30 | // @return [Request] a default request object 31 | func GetRequestSubuser(key, endpoint, host, subuser string) rest.Request { 32 | return createSendGridRequest(sendGridOptions{key, endpoint, host, subuser}) 33 | } 34 | 35 | // createSendGridRequest create Request 36 | // @return [Request] a default request object 37 | func createSendGridRequest(sgOptions sendGridOptions) rest.Request { 38 | options := options{ 39 | "Bearer " + sgOptions.Key, 40 | sgOptions.Endpoint, 41 | sgOptions.Host, 42 | sgOptions.Subuser, 43 | } 44 | 45 | if options.Host == "" { 46 | options.Host = "https://api.sendgrid.com" 47 | } 48 | 49 | return requestNew(options) 50 | } 51 | 52 | // NewSendClient constructs a new Twilio SendGrid client given an API key 53 | func NewSendClient(key string) *Client { 54 | request := GetRequest(key, "/v3/mail/send", "") 55 | request.Method = "POST" 56 | return &Client{request} 57 | } 58 | 59 | // extractEndpoint extracts the endpoint from a baseURL 60 | func extractEndpoint(link string) (string, error) { 61 | parsedURL, err := url.Parse(link) 62 | if err != nil { 63 | return "", err 64 | } 65 | 66 | return parsedURL.Path, nil 67 | } 68 | 69 | // SetDataResidency modifies the host as per the region 70 | /* 71 | * This allows support for global and eu regions only. This set will likely expand in the future. 72 | * Global should be the default 73 | * Global region means the message should be sent through: 74 | * HTTP: api.sendgrid.com 75 | * EU region means the message should be sent through: 76 | * HTTP: api.eu.sendgrid.com 77 | */ 78 | // @return [Request] the modified request object 79 | func SetDataResidency(request rest.Request, region string) (rest.Request, error) { 80 | regionalHost, present := allowedRegionsHostMap[region] 81 | if !present { 82 | return request, errors.New("error: region can only be \"eu\" or \"global\"") 83 | } 84 | endpoint, err := extractEndpoint(request.BaseURL) 85 | if err != nil { 86 | return request, err 87 | } 88 | request.BaseURL = regionalHost + endpoint 89 | return request, nil 90 | } 91 | -------------------------------------------------------------------------------- /examples/categories/categories.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | 8 | "github.com/sendgrid/sendgrid-go" 9 | ) 10 | 11 | // Retrieveallcategories : Retrieve all categories 12 | // GET /categories 13 | func Retrieveallcategories() { 14 | apiKey := os.Getenv("SENDGRID_API_KEY") 15 | host := "https://api.sendgrid.com" 16 | request := sendgrid.GetRequest(apiKey, "/v3/categories", host) 17 | request.Method = "GET" 18 | queryParams := make(map[string]string) 19 | queryParams["category"] = "test_string" 20 | queryParams["limit"] = "1" 21 | queryParams["offset"] = "1" 22 | request.QueryParams = queryParams 23 | response, err := sendgrid.API(request) 24 | if err != nil { 25 | log.Println(err) 26 | } else { 27 | fmt.Println(response.StatusCode) 28 | fmt.Println(response.Body) 29 | fmt.Println(response.Headers) 30 | } 31 | } 32 | 33 | // RetrieveEmailStatisticsforCategories : Retrieve Email Statistics for Categories 34 | // GET /categories/stats 35 | func RetrieveEmailStatisticsforCategories() { 36 | apiKey := os.Getenv("SENDGRID_API_KEY") 37 | host := "https://api.sendgrid.com" 38 | request := sendgrid.GetRequest(apiKey, "/v3/categories/stats", host) 39 | request.Method = "GET" 40 | queryParams := make(map[string]string) 41 | queryParams["end_date"] = "2016-04-01" 42 | queryParams["aggregated_by"] = "day" 43 | queryParams["limit"] = "1" 44 | queryParams["offset"] = "1" 45 | queryParams["start_date"] = "2016-01-01" 46 | queryParams["categories"] = "test_string" 47 | request.QueryParams = queryParams 48 | response, err := sendgrid.API(request) 49 | if err != nil { 50 | log.Println(err) 51 | } else { 52 | fmt.Println(response.StatusCode) 53 | fmt.Println(response.Body) 54 | fmt.Println(response.Headers) 55 | } 56 | } 57 | 58 | // Retrievesumsofemailstatsforeachcategory : Retrieve sums of email stats for each category [Needs: Stats object -- 59 | // -- defined, has category ID?] 60 | // GET /categories/stats/sums 61 | func Retrievesumsofemailstatsforeachcategory() { 62 | apiKey := os.Getenv("SENDGRID_API_KEY") 63 | host := "https://api.sendgrid.com" 64 | request := sendgrid.GetRequest(apiKey, "/v3/categories/stats/sums", host) 65 | request.Method = "GET" 66 | queryParams := make(map[string]string) 67 | queryParams["end_date"] = "2016-04-01" 68 | queryParams["aggregated_by"] = "day" 69 | queryParams["limit"] = "1" 70 | queryParams["sort_by_metric"] = "test_string" 71 | queryParams["offset"] = "1" 72 | queryParams["start_date"] = "2016-01-01" 73 | queryParams["sort_by_direction"] = "asc" 74 | request.QueryParams = queryParams 75 | response, err := sendgrid.API(request) 76 | if err != nil { 77 | log.Println(err) 78 | } else { 79 | fmt.Println(response.StatusCode) 80 | fmt.Println(response.Body) 81 | fmt.Println(response.Headers) 82 | } 83 | } 84 | 85 | func main() { 86 | // add your function calls here 87 | } 88 | -------------------------------------------------------------------------------- /.github/workflows/test-and-deploy.yml: -------------------------------------------------------------------------------- 1 | name: Test and Deploy 2 | on: 3 | push: 4 | branches: [ '*' ] 5 | tags: [ '*' ] 6 | pull_request: 7 | branches: [ main ] 8 | schedule: 9 | # Run automatically at 8AM PST Monday-Friday 10 | - cron: '0 15 * * 1-5' 11 | workflow_dispatch: 12 | 13 | jobs: 14 | test: 15 | name: Build & Test 16 | runs-on: ubuntu-latest 17 | timeout-minutes: 20 18 | strategy: 19 | matrix: 20 | go: [ '1.14', '1.15', '1.16', '1.17', '1.18', '1.19' ] 21 | env: 22 | DOCKER_LOGIN: ${{ secrets.DOCKER_USERNAME && secrets.DOCKER_AUTH_TOKEN }} 23 | steps: 24 | - name: Checkout sendgrid-go 25 | uses: actions/checkout@v2 26 | 27 | - name: Login to Docker Hub 28 | if: env.DOCKER_LOGIN 29 | uses: docker/login-action@v1 30 | with: 31 | username: ${{ secrets.DOCKER_USERNAME }} 32 | password: ${{ secrets.DOCKER_AUTH_TOKEN }} 33 | 34 | - name: Setup Go environment 35 | uses: actions/setup-go@v2 36 | with: 37 | go-version: ${{ matrix.go }} 38 | 39 | - name: Set Go env vars 40 | run: | 41 | echo "GOPATH=$HOME" >> $GITHUB_ENV 42 | echo "GOBIN=$HOME/bin" >> $GITHUB_ENV 43 | echo "GO111MODULE=off" >> $GITHUB_ENV 44 | 45 | - name: Install Docker Compose 46 | run: | 47 | sudo apt-get update 48 | sudo apt-get install -y docker-compose 49 | 50 | - name: Run Tests 51 | run: make test-docker 52 | 53 | deploy: 54 | name: Deploy 55 | if: success() && github.ref_type == 'tag' 56 | needs: [ test ] 57 | runs-on: ubuntu-latest 58 | steps: 59 | - name: Checkout sendgrid-go 60 | uses: actions/checkout@v2 61 | 62 | - name: Create GitHub Release 63 | uses: sendgrid/dx-automator/actions/release@main 64 | env: 65 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 66 | 67 | - name: Submit metric to Datadog 68 | uses: sendgrid/dx-automator/actions/datadog-release-metric@main 69 | env: 70 | DD_API_KEY: ${{ secrets.DATADOG_API_KEY }} 71 | 72 | notify-on-failure: 73 | name: Slack notify on failure 74 | if: failure() && github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || github.ref_type == 'tag') 75 | needs: [ test, deploy ] 76 | runs-on: ubuntu-latest 77 | steps: 78 | - uses: rtCamp/action-slack-notify@v2 79 | env: 80 | SLACK_COLOR: failure 81 | SLACK_ICON_EMOJI: ':github:' 82 | SLACK_MESSAGE: ${{ format('Test *{0}*, Deploy *{1}*, {2}/{3}/actions/runs/{4}', needs.test.result, needs.deploy.result, github.server_url, github.repository, github.run_id) }} 83 | SLACK_TITLE: Action Failure - ${{ github.repository }} 84 | SLACK_USERNAME: GitHub Actions 85 | SLACK_MSG_AUTHOR: twilio-dx 86 | SLACK_FOOTER: Posted automatically using GitHub Actions 87 | SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} 88 | MSG_MINIMAL: true 89 | -------------------------------------------------------------------------------- /examples/dataresidency/setRegion.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | 8 | "github.com/sendgrid/rest" 9 | "github.com/sendgrid/sendgrid-go/helpers/mail" 10 | 11 | "github.com/sendgrid/sendgrid-go" 12 | ) 13 | 14 | var SAMPLE_EMAIL = "test@example.com" 15 | 16 | // SetDataResidency : Set region for sendgrid. 17 | func SetDataResidencyGlobal() { 18 | message := buildHelloEmail() 19 | request, err := buildSendgridObj("global") 20 | if err != nil { 21 | log.Println(err) 22 | } else { 23 | request.Body = mail.GetRequestBody(message) 24 | response, err := sendgrid.API(request) 25 | if err != nil { 26 | log.Println(err) 27 | } else { 28 | fmt.Println(response.StatusCode) 29 | fmt.Println(response.Body) 30 | fmt.Println(response.Headers) 31 | } 32 | } 33 | } 34 | 35 | func SetDataResidencyEu() { 36 | message := buildHelloEmail() 37 | request, err := buildSendgridObj("eu") 38 | if err != nil { 39 | log.Println(err) 40 | } else { 41 | request.Body = mail.GetRequestBody(message) 42 | response, err := sendgrid.API(request) 43 | if err != nil { 44 | log.Println(err) 45 | } else { 46 | fmt.Println(response.StatusCode) 47 | fmt.Println(response.Body) 48 | fmt.Println(response.Headers) 49 | } 50 | } 51 | } 52 | 53 | func SetDataResidencyDefault() { 54 | message := buildHelloEmail() 55 | request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KEY"), "/v3/mail/send", "") 56 | request.Method = "POST" 57 | request.Body = mail.GetRequestBody(message) 58 | response, err := sendgrid.API(request) 59 | if err != nil { 60 | log.Println(err) 61 | } else { 62 | fmt.Println(response.StatusCode) 63 | fmt.Println(response.Body) 64 | fmt.Println(response.Headers) 65 | } 66 | } 67 | 68 | func buildHelloEmail() *mail.SGMailV3 { 69 | // Note that when you use this constructor an initial personalization object 70 | // is created for you. It can be accessed via 71 | // mail.personalization.get(0) as it is a List object 72 | 73 | from := mail.NewEmail("test_user", SAMPLE_EMAIL) 74 | subject := "Sending with Twilio SendGrid is Fun" 75 | to := mail.NewEmail("test_user", SAMPLE_EMAIL) 76 | plainTextContent := "and easy to do anywhere, even with Go" 77 | htmlContent := "and easy to do anywhere, even with Go" 78 | message := mail.NewSingleEmail(from, subject, to, plainTextContent, htmlContent) 79 | email := mail.NewEmail("test_user", SAMPLE_EMAIL) 80 | 81 | p := mail.NewPersonalization() 82 | p.AddTos(email) 83 | message.AddPersonalizations(p) 84 | 85 | return message 86 | } 87 | 88 | func buildSendgridObj(region string) (rest.Request, error) { 89 | request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KEY"), "/v3/mail/send", "") 90 | request.Method = "POST" 91 | request, err := sendgrid.SetDataResidency(request, region) 92 | if err != nil { 93 | return request, err 94 | } 95 | return request, nil 96 | } 97 | 98 | func main() { 99 | // add your function calls here 100 | } 101 | -------------------------------------------------------------------------------- /FIRST_TIMERS.md: -------------------------------------------------------------------------------- 1 | # How To Contribute to Twilio SendGrid Repositories via GitHub 2 | Contributing to the Twilio SendGrid repositories is easy! All you need to do is find an open issue (see the bottom of this page for a list of repositories containing open issues), fix it and submit a pull request. Once you have submitted your pull request, the team can easily review it before it is merged into the repository. 3 | 4 | To make a pull request, follow these steps: 5 | 6 | 1. Log into GitHub. If you do not already have a GitHub account, you will have to create one in order to submit a change. Click the Sign up link in the upper right-hand corner to create an account. Enter your username, password, and email address. If you are an employee of Twilio SendGrid, please use your full name with your GitHub account and enter Twilio SendGrid as your company so we can easily identify you. 7 | 8 | 9 | 10 | 2. __[Fork](https://help.github.com/fork-a-repo/)__ the [sendgrid-go](https://github.com/sendgrid/sendgrid-go) repository: 11 | 12 | 13 | 14 | 3. __Clone__ your fork via the following commands: 15 | 16 | ```bash 17 | # Clone your fork of the repo into the current directory 18 | git clone https://github.com/your_username/sendgrid-go 19 | # Navigate to the newly cloned directory 20 | cd sendgrid-go 21 | # Assign the original repo to a remote called "upstream" 22 | git remote add upstream https://github.com/sendgrid/sendgrid-go 23 | ``` 24 | 25 | > Don't forget to replace *your_username* in the URL by your real GitHub username. 26 | 27 | 4. __Create a new topic branch__ (off the main project development branch) to contain your feature, change, or fix: 28 | 29 | ```bash 30 | git checkout -b 31 | ``` 32 | 33 | 5. __Commit your changes__ in logical chunks. 34 | 35 | Please adhere to these [git commit message guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) or your code is unlikely be merged into the main project. Use Git's [interactive rebase](https://help.github.com/articles/interactive-rebase) feature to tidy up your commits before making them public. Probably you will also have to create tests (if needed) or create or update the example code that demonstrates the functionality of this change to the code. 36 | 37 | 6. __Locally merge (or rebase)__ the upstream development branch into your topic branch: 38 | 39 | ```bash 40 | git pull [--rebase] upstream main 41 | ``` 42 | 43 | 7. __Push__ your topic branch up to your fork: 44 | 45 | ```bash 46 | git push origin 47 | ``` 48 | 49 | 8. __[Open a Pull Request](https://help.github.com/articles/creating-a-pull-request/#changing-the-branch-range-and-destination-repository/)__ with a clear title and description against the `main` branch. All tests must be passing before we will review the PR. 50 | 51 | ## Important notice 52 | 53 | Before creating a pull request, make sure that you respect the repository's constraints regarding contributions. You can find them in the [CONTRIBUTING.md](CONTRIBUTING.md) file. 54 | -------------------------------------------------------------------------------- /examples/alerts/alerts.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | 8 | "github.com/sendgrid/sendgrid-go" 9 | ) 10 | 11 | // CreateanewAlert : Create a new Alert 12 | // POST /alerts 13 | func CreateanewAlert() { 14 | apiKey := os.Getenv("SENDGRID_API_KEY") 15 | host := "https://api.sendgrid.com" 16 | request := sendgrid.GetRequest(apiKey, "/v3/alerts", host) 17 | request.Method = "POST" 18 | request.Body = []byte(` { 19 | "email_to": "example@example.com", 20 | "frequency": "daily", 21 | "type": "stats_notification" 22 | }`) 23 | response, err := sendgrid.API(request) 24 | if err != nil { 25 | log.Println(err) 26 | } else { 27 | fmt.Println(response.StatusCode) 28 | fmt.Println(response.Body) 29 | fmt.Println(response.Headers) 30 | } 31 | } 32 | 33 | // Retrieveallalerts : Retrieve all alerts 34 | // GET /alerts 35 | func Retrieveallalerts() { 36 | apiKey := os.Getenv("SENDGRID_API_KEY") 37 | host := "https://api.sendgrid.com" 38 | request := sendgrid.GetRequest(apiKey, "/v3/alerts", host) 39 | request.Method = "GET" 40 | response, err := sendgrid.API(request) 41 | if err != nil { 42 | log.Println(err) 43 | } else { 44 | fmt.Println(response.StatusCode) 45 | fmt.Println(response.Body) 46 | fmt.Println(response.Headers) 47 | } 48 | } 49 | 50 | // Updateanalert : Update an alert 51 | // PATCH /alerts/{alert_id} 52 | func Updateanalert() { 53 | apiKey := os.Getenv("SENDGRID_API_KEY") 54 | host := "https://api.sendgrid.com" 55 | request := sendgrid.GetRequest(apiKey, "/v3/alerts/{alert_id}", host) 56 | request.Method = "PATCH" 57 | request.Body = []byte(` { 58 | "email_to": "example@example.com" 59 | }`) 60 | response, err := sendgrid.API(request) 61 | if err != nil { 62 | log.Println(err) 63 | } else { 64 | fmt.Println(response.StatusCode) 65 | fmt.Println(response.Body) 66 | fmt.Println(response.Headers) 67 | } 68 | } 69 | 70 | // Retrieveaspecificalert : Retrieve a specific alert 71 | // GET /alerts/{alert_id} 72 | func Retrieveaspecificalert() { 73 | apiKey := os.Getenv("SENDGRID_API_KEY") 74 | host := "https://api.sendgrid.com" 75 | request := sendgrid.GetRequest(apiKey, "/v3/alerts/{alert_id}", host) 76 | request.Method = "GET" 77 | response, err := sendgrid.API(request) 78 | if err != nil { 79 | log.Println(err) 80 | } else { 81 | fmt.Println(response.StatusCode) 82 | fmt.Println(response.Body) 83 | fmt.Println(response.Headers) 84 | } 85 | } 86 | 87 | // Deleteanalert : Delete an alert 88 | // DELETE /alerts/{alert_id} 89 | func Deleteanalert() { 90 | apiKey := os.Getenv("SENDGRID_API_KEY") 91 | host := "https://api.sendgrid.com" 92 | request := sendgrid.GetRequest(apiKey, "/v3/alerts/{alert_id}", host) 93 | request.Method = "DELETE" 94 | response, err := sendgrid.API(request) 95 | if err != nil { 96 | log.Println(err) 97 | } else { 98 | fmt.Println(response.StatusCode) 99 | fmt.Println(response.Body) 100 | fmt.Println(response.Headers) 101 | } 102 | } 103 | 104 | func main() { 105 | // add your function calls here 106 | } 107 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | - Using welcoming and inclusive language 18 | - Being respectful of differing viewpoints and experiences 19 | - Gracefully accepting constructive criticism 20 | - Focusing on what is best for the community 21 | - Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | - The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | - Trolling, insulting/derogatory comments, and personal or political attacks 28 | - Public or private harassment 29 | - Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | - Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at open-source@twilio.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | -------------------------------------------------------------------------------- /examples/apikeys/apikeys.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | 8 | sendgrid "github.com/sendgrid/sendgrid-go" 9 | ) 10 | 11 | // CreateAPIkeys : Create API keys 12 | // POST /api_keys 13 | func CreateAPIkeys() { 14 | apiKey := os.Getenv("SENDGRID_API_KEY") 15 | host := "https://api.sendgrid.com" 16 | request := sendgrid.GetRequest(apiKey, "/v3/api_keys", host) 17 | request.Method = "POST" 18 | request.Body = []byte(` { 19 | "name": "My API Key", 20 | "sample": "data", 21 | "scopes": [ 22 | "mail.send", 23 | "alerts.create", 24 | "alerts.read" 25 | ] 26 | }`) 27 | response, err := sendgrid.API(request) 28 | if err != nil { 29 | log.Println(err) 30 | } else { 31 | fmt.Println(response.StatusCode) 32 | fmt.Println(response.Body) 33 | fmt.Println(response.Headers) 34 | } 35 | } 36 | 37 | // RetrieveallAPIKeysbelongingtotheauthenticateduser : Retrieve all API Keys belonging to the authenticated user 38 | // GET /api_keys 39 | func RetrieveallAPIKeysbelongingtotheauthenticateduser() { 40 | apiKey := os.Getenv("SENDGRID_API_KEY") 41 | host := "https://api.sendgrid.com" 42 | request := sendgrid.GetRequest(apiKey, "/v3/api_keys", host) 43 | request.Method = "GET" 44 | queryParams := make(map[string]string) 45 | queryParams["limit"] = "1" 46 | request.QueryParams = queryParams 47 | response, err := sendgrid.API(request) 48 | if err != nil { 49 | log.Println(err) 50 | } else { 51 | fmt.Println(response.StatusCode) 52 | fmt.Println(response.Body) 53 | fmt.Println(response.Headers) 54 | } 55 | } 56 | 57 | // UpdatethenamescopesofanAPIKey : Update the name & scopes of an API Key 58 | // PUT /api_keys/{api_key_id} 59 | func UpdatethenamescopesofanAPIKey() { 60 | apiKey := os.Getenv("SENDGRID_API_KEY") 61 | host := "https://api.sendgrid.com" 62 | request := sendgrid.GetRequest(apiKey, "/v3/api_keys/{api_key_id}", host) 63 | request.Method = "PUT" 64 | request.Body = []byte(` { 65 | "name": "A New Hope", 66 | "scopes": [ 67 | "user.profile.read", 68 | "user.profile.update" 69 | ] 70 | }`) 71 | response, err := sendgrid.API(request) 72 | if err != nil { 73 | log.Println(err) 74 | } else { 75 | fmt.Println(response.StatusCode) 76 | fmt.Println(response.Body) 77 | fmt.Println(response.Headers) 78 | } 79 | } 80 | 81 | // UpdateAPIkeys : Update API keys 82 | // PATCH /api_keys/{api_key_id} 83 | func UpdateAPIkeys() { 84 | apiKey := os.Getenv("SENDGRID_API_KEY") 85 | host := "https://api.sendgrid.com" 86 | request := sendgrid.GetRequest(apiKey, "/v3/api_keys/{api_key_id}", host) 87 | request.Method = "PATCH" 88 | request.Body = []byte(` { 89 | "name": "A New Hope" 90 | }`) 91 | response, err := sendgrid.API(request) 92 | if err != nil { 93 | log.Println(err) 94 | } else { 95 | fmt.Println(response.StatusCode) 96 | fmt.Println(response.Body) 97 | fmt.Println(response.Headers) 98 | } 99 | } 100 | 101 | // RetrieveanexistingAPIKey : Retrieve an existing API Key 102 | // GET /api_keys/{api_key_id} 103 | func RetrieveanexistingAPIKey() { 104 | apiKey := os.Getenv("SENDGRID_API_KEY") 105 | host := "https://api.sendgrid.com" 106 | request := sendgrid.GetRequest(apiKey, "/v3/api_keys/{api_key_id}", host) 107 | request.Method = "GET" 108 | response, err := sendgrid.API(request) 109 | if err != nil { 110 | log.Println(err) 111 | } else { 112 | fmt.Println(response.StatusCode) 113 | fmt.Println(response.Body) 114 | fmt.Println(response.Headers) 115 | } 116 | } 117 | 118 | // DeleteAPIkeys : Delete API keys 119 | // DELETE /api_keys/{api_key_id} 120 | func DeleteAPIkeys() { 121 | apiKey := os.Getenv("SENDGRID_API_KEY") 122 | host := "https://api.sendgrid.com" 123 | request := sendgrid.GetRequest(apiKey, "/v3/api_keys/{api_key_id}", host) 124 | request.Method = "DELETE" 125 | response, err := sendgrid.API(request) 126 | if err != nil { 127 | log.Println(err) 128 | } else { 129 | fmt.Println(response.StatusCode) 130 | fmt.Println(response.Body) 131 | fmt.Println(response.Headers) 132 | } 133 | } 134 | 135 | func main() { 136 | // add your function calls here 137 | } 138 | -------------------------------------------------------------------------------- /examples/accesssettings/accesssettings.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | 8 | sendgrid "github.com/sendgrid/sendgrid-go" 9 | ) 10 | 11 | // Retrieveallrecentaccessattempts : Retrieve all recent access attempts 12 | // GET /access_settings/activity 13 | func Retrieveallrecentaccessattempts() { 14 | apiKey := os.Getenv("SENDGRID_API_KEY") 15 | host := "https://api.sendgrid.com" 16 | request := sendgrid.GetRequest(apiKey, "/v3/access_settings/activity", host) 17 | request.Method = "GET" 18 | queryParams := make(map[string]string) 19 | queryParams["limit"] = "1" 20 | request.QueryParams = queryParams 21 | response, err := sendgrid.API(request) 22 | if err != nil { 23 | log.Println(err) 24 | } else { 25 | fmt.Println(response.StatusCode) 26 | fmt.Println(response.Body) 27 | fmt.Println(response.Headers) 28 | } 29 | } 30 | 31 | // AddoneormoreIPstothewhitelist : Add one or more IPs to the whitelist 32 | // POST /access_settings/whitelist 33 | func AddoneormoreIPstothewhitelist() { 34 | apiKey := os.Getenv("SENDGRID_API_KEY") 35 | host := "https://api.sendgrid.com" 36 | request := sendgrid.GetRequest(apiKey, "/v3/access_settings/whitelist", host) 37 | request.Method = "POST" 38 | request.Body = []byte(` { 39 | "ips": [ 40 | { 41 | "ip": "192.168.1.1" 42 | }, 43 | { 44 | "ip": "192.*.*.*" 45 | }, 46 | { 47 | "ip": "192.168.1.3/32" 48 | } 49 | ] 50 | }`) 51 | response, err := sendgrid.API(request) 52 | if err != nil { 53 | log.Println(err) 54 | } else { 55 | fmt.Println(response.StatusCode) 56 | fmt.Println(response.Body) 57 | fmt.Println(response.Headers) 58 | } 59 | } 60 | 61 | // RetrievealistofcurrentlywhitelistedIPs : Retrieve a list of currently whitelisted IPs 62 | // GET /access_settings/whitelist 63 | func RetrievealistofcurrentlywhitelistedIPs() { 64 | apiKey := os.Getenv("SENDGRID_API_KEY") 65 | host := "https://api.sendgrid.com" 66 | request := sendgrid.GetRequest(apiKey, "/v3/access_settings/whitelist", host) 67 | request.Method = "GET" 68 | response, err := sendgrid.API(request) 69 | if err != nil { 70 | log.Println(err) 71 | } else { 72 | fmt.Println(response.StatusCode) 73 | fmt.Println(response.Body) 74 | fmt.Println(response.Headers) 75 | } 76 | } 77 | 78 | // RemoveoneormoreIPsfromthewhitelist : Remove one or more IPs from the whitelist 79 | // DELETE /access_settings/whitelist 80 | func RemoveoneormoreIPsfromthewhitelist() { 81 | apiKey := os.Getenv("SENDGRID_API_KEY") 82 | host := "https://api.sendgrid.com" 83 | request := sendgrid.GetRequest(apiKey, "/v3/access_settings/whitelist", host) 84 | request.Method = "DELETE" 85 | request.Body = []byte(` { 86 | "ids": [ 87 | 1, 88 | 2, 89 | 3 90 | ] 91 | }`) 92 | response, err := sendgrid.API(request) 93 | if err != nil { 94 | log.Println(err) 95 | } else { 96 | fmt.Println(response.StatusCode) 97 | fmt.Println(response.Body) 98 | fmt.Println(response.Headers) 99 | } 100 | } 101 | 102 | // RetrieveaspecificwhitelistedIP : Retrieve a specific whitelisted IP 103 | // GET /access_settings/whitelist/{rule_id} 104 | func RetrieveaspecificwhitelistedIP() { 105 | apiKey := os.Getenv("SENDGRID_API_KEY") 106 | host := "https://api.sendgrid.com" 107 | request := sendgrid.GetRequest(apiKey, "/v3/access_settings/whitelist/{rule_id}", host) 108 | request.Method = "GET" 109 | response, err := sendgrid.API(request) 110 | if err != nil { 111 | log.Println(err) 112 | } else { 113 | fmt.Println(response.StatusCode) 114 | fmt.Println(response.Body) 115 | fmt.Println(response.Headers) 116 | } 117 | } 118 | 119 | // RemoveaspecificIPfromthewhitelist : Remove a specific IP from the whitelist 120 | // DELETE /access_settings/whitelist/{rule_id} 121 | func RemoveaspecificIPfromthewhitelist() { 122 | apiKey := os.Getenv("SENDGRID_API_KEY") 123 | host := "https://api.sendgrid.com" 124 | request := sendgrid.GetRequest(apiKey, "/v3/access_settings/whitelist/{rule_id}", host) 125 | request.Method = "DELETE" 126 | response, err := sendgrid.API(request) 127 | if err != nil { 128 | log.Println(err) 129 | } else { 130 | fmt.Println(response.StatusCode) 131 | fmt.Println(response.Body) 132 | fmt.Println(response.Headers) 133 | } 134 | } 135 | 136 | func main() { 137 | // add your function calls here 138 | } 139 | -------------------------------------------------------------------------------- /helpers/eventwebhook/eventwebhook_test.go: -------------------------------------------------------------------------------- 1 | package eventwebhook 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "testing" 8 | 9 | "github.com/stretchr/testify/assert" 10 | "github.com/stretchr/testify/require" 11 | ) 12 | 13 | const ( 14 | publicKey = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE83T4O/n84iotIvIW4mdBgQ/7dAfSmpqIM8kF9mN1flpVKS3GRqe62gw+2fNNRaINXvVpiglSI8eNEc6wEA3F+g==" 15 | signature = "MEUCIGHQVtGj+Y3LkG9fLcxf3qfI10QysgDWmMOVmxG0u6ZUAiEAyBiXDWzM+uOe5W0JuG+luQAbPIqHh89M15TluLtEZtM=" 16 | timestamp = "1600112502" 17 | ) 18 | 19 | func generateTestPayload() []byte { 20 | buffer := &bytes.Buffer{} 21 | encoder := json.NewEncoder(buffer) 22 | encoder.SetEscapeHTML(false) 23 | _ = encoder.Encode([]map[string]interface{}{ 24 | { 25 | "email": "hello@world.com", 26 | "event": "dropped", 27 | "reason": "Bounced Address", 28 | "sg_event_id": "ZHJvcC0xMDk5NDkxOS1MUnpYbF9OSFN0T0doUTRrb2ZTbV9BLTA", 29 | "sg_message_id": "LRzXl_NHStOGhQ4kofSm_A.filterdrecv-p3mdw1-756b745b58-kmzbl-18-5F5FC76C-9.0", 30 | "smtp-id": "", 31 | "timestamp": 1600112492, 32 | }, 33 | }) 34 | payload := buffer.Bytes() 35 | payload = payload[:len(payload)-1] // Drop the trailing newline the encoder adds. 36 | payload = append(payload, []byte("\r\n")...) // Append the expected trailing carriage return and newline! 37 | return payload 38 | } 39 | 40 | func TestEventWebhookNewSettings(t *testing.T) { 41 | assert.NotNil(t, NewSettings(), "NewSettings() shouldn't return nil") 42 | } 43 | 44 | func TestSetEnableSignedWebhook(t *testing.T) { 45 | s := NewSettings() 46 | assert.NotNil(t, NewSettings(), "NewSettings() shouldn't return nil") 47 | 48 | s.SetEnableSignedWebhook(true) 49 | assert.Equal(t, true, *s.EnableSignedWebhook, fmt.Sprintf("EnableSignedWebhook should be 'true', got %v", *s.EnableSignedWebhook)) 50 | 51 | s.SetEnableSignedWebhook(false) 52 | assert.Equal(t, false, *s.EnableSignedWebhook, fmt.Sprintf("EnableSignedWebhook should be 'false', got %v", *s.EnableSignedWebhook)) 53 | } 54 | 55 | func TestSignedWebhookGetRequestBody(t *testing.T) { 56 | expectedJSONEnabled := []byte(`{"enabled":true}`) 57 | expectedJSONDisabled := []byte(`{"enabled":false}`) 58 | 59 | s := NewSettings() 60 | assert.NotNil(t, NewSettings(), "NewSettings() shouldn't return nil") 61 | 62 | s.SetEnableSignedWebhook(false) 63 | actualJSON, err := GetRequestBody(s) 64 | require.NoError(t, err) 65 | assert.Equal(t, expectedJSONDisabled, actualJSON, fmt.Sprintf("EnableSignedWebhook should be '%b', got %b", expectedJSONDisabled, actualJSON)) 66 | 67 | s.SetEnableSignedWebhook(true) 68 | actualJSON, err = GetRequestBody(s) 69 | require.NoError(t, err) 70 | assert.Equal(t, expectedJSONEnabled, actualJSON, fmt.Sprintf("EnableSignedWebhook should be '%b', got %b", expectedJSONEnabled, actualJSON)) 71 | } 72 | 73 | func TestConvertPublicKeyBase64ToECDSA(t *testing.T) { 74 | ecdsaKey, err := ConvertPublicKeyBase64ToECDSA(publicKey) 75 | require.NoError(t, err) 76 | assert.NotNil(t, ecdsaKey, "publicKey shouldn't be nil") 77 | 78 | ecdsaKey, err = ConvertPublicKeyBase64ToECDSA(publicKey + "corrupting the public key") 79 | require.Error(t, err) 80 | assert.Nil(t, ecdsaKey, "publicKey should be nil") 81 | } 82 | 83 | func TestVerifySignature(t *testing.T) { 84 | ecdsaKey, err := ConvertPublicKeyBase64ToECDSA(publicKey) 85 | require.NoError(t, err) 86 | 87 | payload := generateTestPayload() 88 | 89 | // verifications 90 | verified, err := VerifySignature(ecdsaKey, payload, signature, timestamp) 91 | require.NoError(t, err) 92 | assert.True(t, verified) 93 | 94 | // not valid payload 95 | verified, err = VerifySignature(ecdsaKey, []byte("this is not valid payload for the given signature"), signature, timestamp) 96 | require.NoError(t, err) 97 | assert.False(t, verified) 98 | 99 | // not valid signature 100 | verified, err = VerifySignature(ecdsaKey, payload, signature+"causing failure", timestamp) 101 | require.Error(t, err) 102 | assert.False(t, verified) 103 | 104 | // not valid timestamp 105 | verified, err = VerifySignature(ecdsaKey, payload, signature, "invalid timestamp") 106 | require.NoError(t, err) 107 | assert.False(t, verified) 108 | 109 | // empty timestamp 110 | verified, err = VerifySignature(ecdsaKey, payload, signature, "") 111 | require.NoError(t, err) 112 | assert.False(t, verified) 113 | } 114 | -------------------------------------------------------------------------------- /helpers/inbound/README.md: -------------------------------------------------------------------------------- 1 | **This helper is a stand-alone module to help get you started consuming and processing Inbound Parse data.** 2 | 3 | ## Table of Contents 4 | 5 | * [Fields](#fields) 6 | * [Example Usage](#example-usage) 7 | * [Testing the Source Code](#testing) 8 | * [Contributing](#contributing) 9 | 10 | # Fields 11 | 12 | ### ParsedEmail.Envelope 13 | ParsedEmail.Envelope.To and ParsedEmail.Envelope.From represent the exact email addresses that the email was sent to and the exact email address of the sender. There are no special characters and these fields are safe to use without further parsing as email addresses 14 | 15 | ### ParsedEmail.ParsedValues 16 | Please see [SendGrid Docs](https://docs.sendgrid.com/for-developers/parsing-email/setting-up-the-inbound-parse-webhook) to see what fields are available and preparsed by SendGrid. Use these fields over the Headers as they are parsed by SendGrid and gauranteed to be consistent 17 | 18 | ### ParsedEmail.TextBody 19 | this field will satisfy most cases. SendGrid pre-parses the body into a plain text string separated with \n 20 | 21 | ### ParsedEmail.ParsedAttachments 22 | populated **only** when processing the email with ParseWithAttachments(). Provides the following ease of use values 23 | - File: full attachment for uploading or processing (see example to upload to s3) 24 | - Size: file size, useful for filtering or setting upper limits to attachments 25 | - Filename: copies the original filename of the attachment, if there is not one, it defaults to 'Untitled' 26 | - ContentType: the type of file 27 | 28 | ### ParsedEmail.Body 29 | populated *only* when the raw option is checked in the SendGrid Dashboard. Provides the raw HTML body of the email, unless you need to record the exact unparsed HTML payload from the email client, you should use the parsed fields instead. The field is named Body for backward compatability 30 | 31 | ### ParsedEmail.Attachments 32 | populated *only* when the raw option is checked in the SendGrid Dashboard. This field is deprecated. Use ParsedAttachments instead which does not require the Raw setting, and provides parsed values to use and process the attachments 33 | 34 | ### ParsedEmail.Headers 35 | this field is deprecated. Use the SendGrid processed fields in ParsedValues instead. While it maintains its presence to avoid breaking changes, it provides raw, unprocessed headers and not all email clients are compatible. For example. these fields will be empty if the email cient is Outlook.com 36 | 37 | 38 | # Example Usage 39 | 40 | ```go 41 | package main 42 | 43 | import ( 44 | "fmt" 45 | "log" 46 | "net/http" 47 | 48 | "github.com/sendgrid/sendgrid-go/helpers/inbound" 49 | ) 50 | 51 | func inboundHandler(response http.ResponseWriter, request *http.Request) { 52 | parsedEmail, err := ParseWithAttachments(request) 53 | if err != nil { 54 | log.Fatal(err) 55 | } 56 | 57 | fmt.Print(parsedEmail.Envelope.From) 58 | 59 | for filename, contents := range parsedEmail.ParsedAttachments { 60 | // Do something with an attachment 61 | handleAttachment(filename, contents) 62 | } 63 | 64 | 65 | for section, body := range strings.Split(parsedEmail.TextBody, "\n") { 66 | // Do something with the email lines 67 | } 68 | 69 | 70 | // Twilio SendGrid needs a 200 OK response to stop POSTing 71 | response.WriteHeader(http.StatusOK) 72 | } 73 | 74 | // example of uploading an attachment to s3 using the Go sdk-2 75 | func handleAttachment(parsedEmail *ParsedEmail) { 76 | for _, contents := range parsedEmail.ParsedAttachments { 77 | if _, err := sgh.Client.Upload(ctx, &s3.PutObjectInput{ 78 | Bucket: &bucket, 79 | Key: &uploadPath, 80 | Body: contents.File, 81 | ContentType: aws.String(contents.ContentType), 82 | } 83 | } 84 | } 85 | 86 | func main() { 87 | http.HandleFunc("/inbound", inboundHandler) 88 | if err := http.ListenAndServe(":8000", nil); err != nil { 89 | log.Fatalln("Error") 90 | } 91 | } 92 | ``` 93 | 94 | 95 | # Testing the Source Code 96 | 97 | Tests are located in the `helpers/inbound` folder: 98 | 99 | - [inbound_test.go](inbound_test.go) 100 | 101 | Learn about testing this code [here](../../CONTRIBUTING.md#testing). 102 | 103 | 104 | # Contributing 105 | 106 | If you would like to contribute to this project, please see our [contributing guide](../../CONTRIBUTING.md). Thanks! 107 | -------------------------------------------------------------------------------- /examples/senders/senders.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | 8 | "github.com/sendgrid/sendgrid-go" 9 | ) 10 | 11 | // CreateaSenderIdentity : Create a Sender Identity 12 | // POST /senders 13 | func CreateaSenderIdentity() { 14 | apiKey := os.Getenv("SENDGRID_API_KEY") 15 | host := "https://api.sendgrid.com" 16 | request := sendgrid.GetRequest(apiKey, "/v3/senders", host) 17 | request.Method = "POST" 18 | request.Body = []byte(` { 19 | "address": "123 Elm St.", 20 | "address_2": "Apt. 456", 21 | "city": "Denver", 22 | "country": "United States", 23 | "from": { 24 | "email": "from@example.com", 25 | "name": "Example INC" 26 | }, 27 | "nickname": "My Sender ID", 28 | "reply_to": { 29 | "email": "replyto@example.com", 30 | "name": "Example INC" 31 | }, 32 | "state": "Colorado", 33 | "zip": "80202" 34 | }`) 35 | response, err := sendgrid.API(request) 36 | if err != nil { 37 | log.Println(err) 38 | } else { 39 | fmt.Println(response.StatusCode) 40 | fmt.Println(response.Body) 41 | fmt.Println(response.Headers) 42 | } 43 | } 44 | 45 | // GetallSenderIdentities : Get all Sender Identities 46 | // GET /senders 47 | func GetallSenderIdentities() { 48 | apiKey := os.Getenv("SENDGRID_API_KEY") 49 | host := "https://api.sendgrid.com" 50 | request := sendgrid.GetRequest(apiKey, "/v3/senders", host) 51 | request.Method = "GET" 52 | response, err := sendgrid.API(request) 53 | if err != nil { 54 | log.Println(err) 55 | } else { 56 | fmt.Println(response.StatusCode) 57 | fmt.Println(response.Body) 58 | fmt.Println(response.Headers) 59 | } 60 | } 61 | 62 | // UpdateaSenderIdentity : Update a Sender Identity 63 | // PATCH /senders/{sender_id} 64 | func UpdateaSenderIdentity() { 65 | apiKey := os.Getenv("SENDGRID_API_KEY") 66 | host := "https://api.sendgrid.com" 67 | request := sendgrid.GetRequest(apiKey, "/v3/senders/{sender_id}", host) 68 | request.Method = "PATCH" 69 | request.Body = []byte(` { 70 | "address": "123 Elm St.", 71 | "address_2": "Apt. 456", 72 | "city": "Denver", 73 | "country": "United States", 74 | "from": { 75 | "email": "from@example.com", 76 | "name": "Example INC" 77 | }, 78 | "nickname": "My Sender ID", 79 | "reply_to": { 80 | "email": "replyto@example.com", 81 | "name": "Example INC" 82 | }, 83 | "state": "Colorado", 84 | "zip": "80202" 85 | }`) 86 | response, err := sendgrid.API(request) 87 | if err != nil { 88 | log.Println(err) 89 | } else { 90 | fmt.Println(response.StatusCode) 91 | fmt.Println(response.Body) 92 | fmt.Println(response.Headers) 93 | } 94 | } 95 | 96 | // ViewaSenderIdentity : View a Sender Identity 97 | // GET /senders/{sender_id} 98 | func ViewaSenderIdentity() { 99 | apiKey := os.Getenv("SENDGRID_API_KEY") 100 | host := "https://api.sendgrid.com" 101 | request := sendgrid.GetRequest(apiKey, "/v3/senders/{sender_id}", host) 102 | request.Method = "GET" 103 | response, err := sendgrid.API(request) 104 | if err != nil { 105 | log.Println(err) 106 | } else { 107 | fmt.Println(response.StatusCode) 108 | fmt.Println(response.Body) 109 | fmt.Println(response.Headers) 110 | } 111 | } 112 | 113 | // DeleteaSenderIdentity : Delete a Sender Identity 114 | // DELETE /senders/{sender_id} 115 | func DeleteaSenderIdentity() { 116 | apiKey := os.Getenv("SENDGRID_API_KEY") 117 | host := "https://api.sendgrid.com" 118 | request := sendgrid.GetRequest(apiKey, "/v3/senders/{sender_id}", host) 119 | request.Method = "DELETE" 120 | response, err := sendgrid.API(request) 121 | if err != nil { 122 | log.Println(err) 123 | } else { 124 | fmt.Println(response.StatusCode) 125 | fmt.Println(response.Body) 126 | fmt.Println(response.Headers) 127 | } 128 | } 129 | 130 | // ResendSenderIdentityVerification : Resend Sender Identity Verification 131 | // POST /senders/{sender_id}/resend_verification 132 | func ResendSenderIdentityVerification() { 133 | apiKey := os.Getenv("SENDGRID_API_KEY") 134 | host := "https://api.sendgrid.com" 135 | request := sendgrid.GetRequest(apiKey, "/v3/senders/{sender_id}/resend_verification", host) 136 | request.Method = "POST" 137 | response, err := sendgrid.API(request) 138 | if err != nil { 139 | log.Println(err) 140 | } else { 141 | fmt.Println(response.StatusCode) 142 | fmt.Println(response.Body) 143 | fmt.Println(response.Headers) 144 | } 145 | } 146 | 147 | func main() { 148 | // add your function calls here 149 | } 150 | -------------------------------------------------------------------------------- /helpers/inbound/inbound_test.go: -------------------------------------------------------------------------------- 1 | package inbound 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "log" 7 | "net/http" 8 | "os" 9 | "testing" 10 | 11 | "github.com/stretchr/testify/assert" 12 | ) 13 | 14 | func createRequest(filename string) *http.Request { 15 | file, err := os.ReadFile(filename) 16 | if err != nil { 17 | return nil 18 | } 19 | 20 | // Build POST request 21 | req, _ := http.NewRequest(http.MethodPost, "", bytes.NewReader(file)) 22 | req.Header.Set("Content-Type", "multipart/form-data; boundary=xYzZY") 23 | req.Header.Set("User-Agent", "Twilio-SendGrid-Test") 24 | return req 25 | } 26 | 27 | func TestParse(t *testing.T) { 28 | // Build a table of tests to run with each one having a name, the sample data file to post, 29 | // and the expected HTTP response from the handler 30 | tests := []struct { 31 | name string 32 | file string 33 | expectedError error 34 | }{ 35 | { 36 | name: "NoAttachment", 37 | file: "./sample_data/raw_data.txt", 38 | }, 39 | { 40 | name: "Attachment", 41 | file: "./sample_data/raw_data_with_attachments.txt", 42 | }, 43 | { 44 | name: "DefaultData", 45 | file: "./sample_data/default_data.txt", 46 | }, 47 | { 48 | name: "BadData", 49 | file: "./sample_data/bad_data.txt", 50 | expectedError: fmt.Errorf("multipart: NextPart: EOF"), 51 | }, 52 | } 53 | 54 | for _, test := range tests { 55 | t.Run(test.name, func(subTest *testing.T) { 56 | //Load POST body 57 | req := createRequest(test.file) 58 | 59 | // Invoke callback handler 60 | email, err := Parse(req) 61 | if test.expectedError != nil { 62 | assert.Error(subTest, err, "expected an error to occur") 63 | return 64 | } 65 | 66 | assert.NoError(subTest, err, "did NOT expect an error to occur") 67 | 68 | from := "Example User " 69 | assert.Equalf(subTest, email.Headers["From"], from, "Expected From: %s, Got: %s", from, email.Headers["From"]) 70 | }) 71 | } 72 | } 73 | 74 | func ExampleParsedEmail_parseHeaders() { 75 | headers := ` 76 | Foo: foo 77 | Bar: baz 78 | ` 79 | email := ParsedEmail{ 80 | Headers: make(map[string]string), 81 | Body: make(map[string]string), 82 | Attachments: make(map[string][]byte), 83 | rawRequest: nil, 84 | } 85 | email.parseHeaders(headers) 86 | fmt.Println(email.Headers["Foo"]) 87 | fmt.Println(email.Headers["Bar"]) 88 | // Output: 89 | // foo 90 | // baz 91 | } 92 | 93 | func ExampleParsedEmail_parseRawEmail() { 94 | rawEmail := ` 95 | To: test@example.com 96 | From: example@example.com 97 | Subject: Test Email 98 | Content-Type: multipart/mixed; boundary=TwiLIo 99 | 100 | --TwiLIo 101 | Content-Type: text/plain; charset=UTF-8 102 | 103 | Hello Twilio SendGrid! 104 | --TwiLIo 105 | Content-Type: text/html; charset=UTF-8 106 | Content-Transfer-Encoding: quoted-printable 107 | 108 | Hello Twilio SendGrid! 109 | --TwiLIo-- 110 | ` 111 | email := ParsedEmail{ 112 | Headers: make(map[string]string), 113 | Body: make(map[string]string), 114 | Attachments: make(map[string][]byte), 115 | rawRequest: nil, 116 | } 117 | 118 | if err := email.parseRawEmail(rawEmail); err != nil { 119 | log.Fatal(err) 120 | } 121 | 122 | for key, value := range email.Headers { 123 | fmt.Println(key, value) 124 | } 125 | fmt.Println(email.Body["text/plain; charset=UTF-8"]) 126 | // Unordered Output: 127 | // To test@example.com 128 | // From example@example.com 129 | // Subject Test Email 130 | // Content-Type multipart/mixed; boundary=TwiLIo 131 | // Hello Twilio SendGrid! 132 | } 133 | 134 | func TestValidate(t *testing.T) { 135 | tests := []struct { 136 | name string 137 | values map[string][]string 138 | expectedError error 139 | }{ 140 | { 141 | name: "MissingHeaders", 142 | values: map[string][]string{}, 143 | expectedError: fmt.Errorf("missing DKIM and SPF score"), 144 | }, 145 | { 146 | name: "FailedDkim", 147 | values: map[string][]string{"dkim": {"pass", "fail", "pass"}, "SPF": {"pass"}}, 148 | expectedError: fmt.Errorf("DKIM validation failed"), 149 | }, 150 | { 151 | name: "FailedSpf", 152 | values: map[string][]string{"dkim": {"pass", "pass", "pass"}, "SPF": {"pass", "fail", "pass"}}, 153 | expectedError: fmt.Errorf("SPF validation failed"), 154 | }, 155 | { 156 | name: "FailedSpfandDkim", 157 | values: map[string][]string{"dkim": {"pass", "pass", "fail"}, "SPF": {"pass", "fail", "pass"}}, 158 | expectedError: fmt.Errorf("DKIM validation failed"), 159 | }, 160 | { 161 | name: "success", 162 | values: map[string][]string{"dkim": {"pass", "pass", "pass"}, "SPF": {"pass", "pass", "pass"}}, 163 | }, 164 | } 165 | 166 | for _, test := range tests { 167 | t.Run(test.name, func(subTest *testing.T) { 168 | //Load POST body 169 | email := ParsedEmail{rawValues: test.values} 170 | err := email.Validate() 171 | 172 | if test.expectedError != nil { 173 | assert.EqualError(subTest, test.expectedError, err.Error()) 174 | return 175 | } 176 | 177 | assert.NoError(subTest, err, "did NOT expect an error to occur") 178 | }) 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /base_interface.go: -------------------------------------------------------------------------------- 1 | package sendgrid 2 | 3 | import ( 4 | "bytes" 5 | "compress/gzip" 6 | "context" 7 | "errors" 8 | "net/http" 9 | "strconv" 10 | "time" 11 | 12 | "github.com/sendgrid/rest" 13 | "github.com/sendgrid/sendgrid-go/helpers/mail" 14 | ) 15 | 16 | // Version is this client library's current version 17 | const ( 18 | Version = "3.16.1" 19 | rateLimitRetry = 5 20 | rateLimitSleep = 1100 21 | ) 22 | 23 | type options struct { 24 | Auth string 25 | Endpoint string 26 | Host string 27 | Subuser string 28 | } 29 | 30 | // Client is the Twilio SendGrid Go client 31 | type Client struct { 32 | rest.Request 33 | } 34 | 35 | func (o *options) baseURL() string { 36 | return o.Host + o.Endpoint 37 | } 38 | 39 | // requestNew create Request 40 | // @return [Request] a default request object 41 | func requestNew(options options) rest.Request { 42 | requestHeaders := map[string]string{ 43 | "Authorization": options.Auth, 44 | "User-Agent": "sendgrid/" + Version + ";go", 45 | "Accept": "application/json", 46 | } 47 | 48 | if len(options.Subuser) != 0 { 49 | requestHeaders["On-Behalf-Of"] = options.Subuser 50 | } 51 | 52 | return rest.Request{ 53 | BaseURL: options.baseURL(), 54 | Headers: requestHeaders, 55 | } 56 | } 57 | 58 | // Send sends an email through Twilio SendGrid 59 | func (cl *Client) Send(email *mail.SGMailV3) (*rest.Response, error) { 60 | return cl.SendWithContext(context.Background(), email) 61 | } 62 | 63 | // SendWithContext sends an email through Twilio SendGrid with context.Context. 64 | func (cl *Client) SendWithContext(ctx context.Context, email *mail.SGMailV3) (*rest.Response, error) { 65 | cl.Body = mail.GetRequestBody(email) 66 | // when Content-Encoding header is set to "gzip" 67 | // mail body is compressed using gzip according to 68 | // https://docs.sendgrid.com/api-reference/mail-send/mail-send#mail-body-compression 69 | if cl.Headers["Content-Encoding"] == "gzip" { 70 | var gzipped bytes.Buffer 71 | gz := gzip.NewWriter(&gzipped) 72 | if _, err := gz.Write(cl.Body); err != nil { 73 | return nil, err 74 | } 75 | if err := gz.Flush(); err != nil { 76 | return nil, err 77 | } 78 | if err := gz.Close(); err != nil { 79 | return nil, err 80 | } 81 | 82 | cl.Body = gzipped.Bytes() 83 | } 84 | return MakeRequestWithContext(ctx, cl.Request) 85 | } 86 | 87 | // DefaultClient is used if no custom HTTP client is defined 88 | var DefaultClient = rest.DefaultClient 89 | 90 | // API sets up the request to the Twilio SendGrid API, this is main interface. 91 | // Please use the MakeRequest or MakeRequestAsync functions instead. 92 | // (deprecated) 93 | func API(request rest.Request) (*rest.Response, error) { 94 | return MakeRequest(request) 95 | } 96 | 97 | // MakeRequest attempts a Twilio SendGrid request synchronously. 98 | func MakeRequest(request rest.Request) (*rest.Response, error) { 99 | return MakeRequestWithContext(context.Background(), request) 100 | } 101 | 102 | // MakeRequestWithContext attempts a Twilio SendGrid request synchronously with context.Context. 103 | func MakeRequestWithContext(ctx context.Context, request rest.Request) (*rest.Response, error) { 104 | return DefaultClient.SendWithContext(ctx, request) 105 | } 106 | 107 | // MakeRequestRetry a synchronous request, but retry in the event of a rate 108 | // limited response. 109 | func MakeRequestRetry(request rest.Request) (*rest.Response, error) { 110 | return MakeRequestRetryWithContext(context.Background(), request) 111 | } 112 | 113 | // MakeRequestRetryWithContext a synchronous request with context.Context, but retry in the event of a rate 114 | // limited response. 115 | func MakeRequestRetryWithContext(ctx context.Context, request rest.Request) (*rest.Response, error) { 116 | retry := 0 117 | var response *rest.Response 118 | var err error 119 | 120 | for { 121 | select { 122 | case <-ctx.Done(): 123 | return nil, ctx.Err() 124 | default: 125 | } 126 | response, err = MakeRequestWithContext(ctx, request) 127 | if err != nil { 128 | return nil, err 129 | } 130 | 131 | if response.StatusCode != http.StatusTooManyRequests { 132 | return response, nil 133 | } 134 | 135 | if retry > rateLimitRetry { 136 | return nil, errors.New("rate limit retry exceeded") 137 | } 138 | retry++ 139 | 140 | resetTime := time.Now().Add(rateLimitSleep * time.Millisecond) 141 | 142 | reset, ok := response.Headers["X-RateLimit-Reset"] 143 | if ok && len(reset) > 0 { 144 | t, err := strconv.Atoi(reset[0]) 145 | if err == nil { 146 | resetTime = time.Unix(int64(t), 0) 147 | } 148 | } 149 | time.Sleep(resetTime.Sub(time.Now())) 150 | } 151 | } 152 | 153 | // MakeRequestAsync attempts a request asynchronously in a new go 154 | // routine. This function returns two channels: responses 155 | // and errors. This function will retry in the case of a 156 | // rate limit. 157 | func MakeRequestAsync(request rest.Request) (chan *rest.Response, chan error) { 158 | return MakeRequestAsyncWithContext(context.Background(), request) 159 | } 160 | 161 | // MakeRequestAsyncWithContext attempts a request asynchronously in a new go 162 | // routine with context.Context. This function returns two channels: responses 163 | // and errors. This function will retry in the case of a 164 | // rate limit. 165 | func MakeRequestAsyncWithContext(ctx context.Context, request rest.Request) (chan *rest.Response, chan error) { 166 | r := make(chan *rest.Response) 167 | e := make(chan error) 168 | 169 | go func() { 170 | response, err := MakeRequestRetryWithContext(ctx, request) 171 | if err != nil { 172 | e <- err 173 | } 174 | if response != nil { 175 | r <- response 176 | } 177 | }() 178 | 179 | return r, e 180 | } 181 | -------------------------------------------------------------------------------- /TROUBLESHOOTING.md: -------------------------------------------------------------------------------- 1 | If you have an issue logging into your Twilio SendGrid account, please read this [document](https://sendgrid.com/docs/ui/account-and-settings/troubleshooting-login/). For any questions regarding login issues, please contact our [support team](https://support.sendgrid.com). 2 | 3 | If you have a non-library Twilio SendGrid issue, please contact our [support team](https://support.sendgrid.com). 4 | 5 | If you can't find a solution below, please open an [issue](https://github.com/sendgrid/sendgrid-go/issues). 6 | 7 | 8 | ## Table of Contents 9 | 10 | * [Migrating from v2 to v3](#migrating) 11 | * [Continue Using v2](#v2) 12 | * [Testing v3 /mail/send Calls Directly](#testing) 13 | * [Error Messages](#error) 14 | * [Versions](#versions) 15 | * [Environment Variables and Your Twilio SendGrid API Key](#environment) 16 | * [Viewing the Request Body](#request-body) 17 | * [Verifying Event Webhooks](#signed-webhooks) 18 | 19 | 20 | ## Migrating from v2 to v3 21 | 22 | Please review [our guide](https://sendgrid.com/docs/Classroom/Send/v3_Mail_Send/how_to_migrate_from_v2_to_v3_mail_send.html) on how to migrate from v2 to v3. 23 | 24 | 25 | ## Continue Using v2 26 | 27 | [Here](https://github.com/sendgrid/sendgrid-go/tree/0bf6332788d0230b7da84a1ae68d7531073200e1) is the last working version with v2 support. 28 | 29 | Download: 30 | 31 | Click the "Clone or download" green button in [GitHub](https://github.com/sendgrid/sendgrid-go/tree/0bf6332788d0230b7da84a1ae68d7531073200e1) and choose download. 32 | 33 | 34 | ## Testing v3 /mail/send Calls Directly 35 | 36 | [Here](https://sendgrid.com/docs/for-developers/sending-email/curl-examples) are some cURL examples for common use cases. 37 | 38 | 39 | ## Error Messages 40 | 41 | An error is returned if caused by client policy (such as CheckRedirect), or failure to speak HTTP (such as a network connectivity problem). 42 | 43 | To read the error message returned by Twilio SendGrid's API: 44 | 45 | ```go 46 | func main() { 47 | from := mail.NewEmail("Example User", "test@example.com") 48 | subject := "Hello World from the Twilio SendGrid Go Library" 49 | to := mail.NewEmail("Example User", "test@example.com") 50 | content := mail.NewContent("text/plain", "some text here") 51 | m := mail.NewV3MailInit(from, subject, to, content) 52 | 53 | request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KE"), "/v3/mail/send", "https://api.sendgrid.com") 54 | request.Method = "POST" 55 | request.Body = mail.GetRequestBody(m) 56 | response, err := sendgrid.API(request) 57 | if err != nil { 58 | log.Println(err) 59 | } else { 60 | fmt.Println(response.StatusCode) 61 | fmt.Println(response.Body) 62 | fmt.Println(response.Headers) 63 | } 64 | } 65 | ``` 66 | 67 | __CAUTION__: A non-2xx status code doesn't cause an error on sendgrid.API and the application has to verify the response: 68 | 69 | ```golang 70 | resp, err := sendgrid.API(request) 71 | if err != nil { 72 | return err 73 | } 74 | if resp.StatusCode >= 400 { 75 | // something goes wrong and you have to handle (e.g. returning an error to the user or logging the problem) 76 | log.Printf("api response: HTTP %d: %s", resp.StatusCode, resp.Body) 77 | // OR 78 | // return fmt.Errorf("api response: HTTP %d: %s", resp.StatusCode, resp.Body) 79 | } 80 | ``` 81 | 82 | 83 | ## Versions 84 | 85 | We follow the MAJOR.MINOR.PATCH versioning scheme as described by [SemVer.org](http://semver.org). Therefore, we recommend that you always pin (or vendor) the particular version you are working with to your code and never auto-update to the latest version. Especially when there is a MAJOR point release since that is guaranteed to be a breaking change. Changes are documented in the [CHANGELOG](CHANGELOG.md) and [releases](https://github.com/sendgrid/sendgrid-go/releases) section. 86 | 87 | 88 | ## Environment Variables and Your Twilio SendGrid API Key 89 | 90 | All of our examples assume you are using [environment variables](https://github.com/sendgrid/sendgrid-go#setup-environment-variables) to hold your Twilio SendGrid API key. 91 | 92 | If you choose to add your Twilio SendGrid API key directly (not recommended): 93 | 94 | `os.Getenv("SENDGRID_API_KEY")` 95 | 96 | becomes 97 | 98 | `"SENDGRID_API_KEY"` 99 | 100 | In the first case, SENDGRID_API_KEY is in reference to the name of the environment variable, while the second case references the actual Twilio SendGrid API Key. 101 | 102 | 103 | ## Viewing the Request Body 104 | 105 | When debugging or testing, it may be useful to examine the raw request body to compare against the [documented format](https://sendgrid.com/docs/API_Reference/api_v3.html). 106 | 107 | You can do this right before you call `response, err := client.Send(message)` like so: 108 | 109 | ```go 110 | fmt.Println(string(mail.GetRequestBody(message))) 111 | ``` 112 | 113 | 114 | ## Signed Webhook Verification 115 | 116 | Twilio SendGrid's Event Webhook will notify a URL via HTTP POST with information about events that occur as your mail is processed. [This](https://docs.sendgrid.com/for-developers/tracking-events/getting-started-event-webhook-security-features) article covers all you need to know to secure the Event Webhook, allowing you to verify that incoming requests originate from Twilio SendGrid. The sendgrid-go library can help you verify these Signed Event Webhooks. 117 | 118 | You can find the end-to-end usage example [here](helpers/eventwebhook/README.md) and the tests [here](helpers/eventwebhook/eventwebhook_test.go). 119 | If you are still having trouble getting the validation to work, follow the following instructions: 120 | - Be sure to use the *raw* payload for validation 121 | - Be sure to include a trailing carriage return and newline in your payload 122 | - In case of multi-event webhooks, make sure you include the trailing newline and carriage return after *each* event 123 | -------------------------------------------------------------------------------- /examples/mail/mail.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | 8 | "github.com/sendgrid/sendgrid-go" 9 | ) 10 | 11 | // CreateabatchID : Create a batch ID 12 | // POST /mail/batch 13 | func CreateabatchID() { 14 | apiKey := os.Getenv("SENDGRID_API_KEY") 15 | host := "https://api.sendgrid.com" 16 | request := sendgrid.GetRequest(apiKey, "/v3/mail/batch", host) 17 | request.Method = "POST" 18 | response, err := sendgrid.API(request) 19 | if err != nil { 20 | log.Println(err) 21 | } else { 22 | fmt.Println(response.StatusCode) 23 | fmt.Println(response.Body) 24 | fmt.Println(response.Headers) 25 | } 26 | } 27 | 28 | // ValidatebatchID : Validate batch ID 29 | // GET /mail/batch/{batch_id} 30 | func ValidatebatchID() { 31 | apiKey := os.Getenv("SENDGRID_API_KEY") 32 | host := "https://api.sendgrid.com" 33 | request := sendgrid.GetRequest(apiKey, "/v3/mail/batch/{batch_id}", host) 34 | request.Method = "GET" 35 | response, err := sendgrid.API(request) 36 | if err != nil { 37 | log.Println(err) 38 | } else { 39 | fmt.Println(response.StatusCode) 40 | fmt.Println(response.Body) 41 | fmt.Println(response.Headers) 42 | } 43 | } 44 | 45 | // v3MailSend : v3 Mail Send 46 | // POST /mail/send 47 | // This endpoint has a helper, check it out [here](https://github.com/sendgrid/sendgrid-go/blob/HEAD/helpers/mail/README.md). 48 | func v3MailSend() { 49 | apiKey := os.Getenv("SENDGRID_API_KEY") 50 | host := "https://api.sendgrid.com" 51 | request := sendgrid.GetRequest(apiKey, "/v3/mail/send", host) 52 | request.Method = "POST" 53 | request.Body = []byte(` { 54 | "asm": { 55 | "group_id": 1, 56 | "groups_to_display": [ 57 | 1, 58 | 2, 59 | 3 60 | ] 61 | }, 62 | "attachments": [ 63 | { 64 | "content": "[BASE64 encoded content block here]", 65 | "content_id": "ii_139db99fdb5c3704", 66 | "disposition": "inline", 67 | "filename": "file1.jpg", 68 | "name": "file1", 69 | "type": "jpg" 70 | } 71 | ], 72 | "batch_id": "[YOUR BATCH ID GOES HERE]", 73 | "categories": [ 74 | "category1", 75 | "category2" 76 | ], 77 | "content": [ 78 | { 79 | "type": "text/html", 80 | "value": "

Hello, world!

" 81 | } 82 | ], 83 | "custom_args": { 84 | "New Argument 1": "New Value 1", 85 | "activationAttempt": "1", 86 | "customerAccountNumber": "[CUSTOMER ACCOUNT NUMBER GOES HERE]" 87 | }, 88 | "from": { 89 | "email": "sam.smith@example.com", 90 | "name": "Sam Smith" 91 | }, 92 | "headers": {}, 93 | "ip_pool_name": "[YOUR POOL NAME GOES HERE]", 94 | "mail_settings": { 95 | "bcc": { 96 | "email": "ben.doe@example.com", 97 | "enable": true 98 | }, 99 | "bypass_list_management": { 100 | "enable": true 101 | }, 102 | "footer": { 103 | "enable": true, 104 | "html": "

Thanks
The Twilio SendGrid Team

", 105 | "text": "Thanks,/n The Twilio SendGrid Team" 106 | }, 107 | "sandbox_mode": { 108 | "enable": false 109 | }, 110 | "spam_check": { 111 | "enable": true, 112 | "post_to_url": "http://example.com/compliance", 113 | "threshold": 3 114 | } 115 | }, 116 | "personalizations": [ 117 | { 118 | "bcc": [ 119 | { 120 | "email": "sam.doe@example.com", 121 | "name": "Sam Doe" 122 | } 123 | ], 124 | "cc": [ 125 | { 126 | "email": "jane.doe@example.com", 127 | "name": "Jane Doe" 128 | } 129 | ], 130 | "custom_args": { 131 | "New Argument 1": "New Value 1", 132 | "activationAttempt": "1", 133 | "customerAccountNumber": "[CUSTOMER ACCOUNT NUMBER GOES HERE]" 134 | }, 135 | "headers": { 136 | "X-Accept-Language": "en", 137 | "X-Mailer": "MyApp" 138 | }, 139 | "send_at": 1409348513, 140 | "subject": "Hello, World!", 141 | "substitutions": { 142 | "id": "substitutions", 143 | "type": "object" 144 | }, 145 | "from": { 146 | "email": "bob.doe@example.com", 147 | "name": "Bob Doe" 148 | }, 149 | "to": [ 150 | { 151 | "email": "john.doe@example.com", 152 | "name": "John Doe" 153 | } 154 | ] 155 | } 156 | ], 157 | "reply_to": { 158 | "email": "sam.smith@example.com", 159 | "name": "Sam Smith" 160 | }, 161 | "sections": { 162 | "section": { 163 | ":sectionName1": "section 1 text", 164 | ":sectionName2": "section 2 text" 165 | } 166 | }, 167 | "send_at": 1409348513, 168 | "subject": "Hello, World!", 169 | "template_id": "[YOUR TEMPLATE ID GOES HERE]", 170 | "tracking_settings": { 171 | "click_tracking": { 172 | "enable": true, 173 | "enable_text": true 174 | }, 175 | "ganalytics": { 176 | "enable": true, 177 | "utm_campaign": "[NAME OF YOUR REFERRER SOURCE]", 178 | "utm_content": "[USE THIS SPACE TO DIFFERENTIATE YOUR EMAIL FROM ADS]", 179 | "utm_medium": "[NAME OF YOUR MARKETING MEDIUM e.g. email]", 180 | "utm_name": "[NAME OF YOUR CAMPAIGN]", 181 | "utm_term": "[IDENTIFY PAID KEYWORDS HERE]" 182 | }, 183 | "open_tracking": { 184 | "enable": true, 185 | "substitution_tag": "%opentrack" 186 | }, 187 | "subscription_tracking": { 188 | "enable": true, 189 | "html": "If you would like to unsubscribe and stop receiving these emails <% clickhere %>.", 190 | "substitution_tag": "<%click here%>", 191 | "text": "If you would like to unsubscribe and stop receiveing these emails <% click here %>." 192 | } 193 | } 194 | }`) 195 | response, err := sendgrid.API(request) 196 | if err != nil { 197 | log.Println(err) 198 | } else { 199 | fmt.Println(response.StatusCode) 200 | fmt.Println(response.Body) 201 | fmt.Println(response.Headers) 202 | } 203 | } 204 | 205 | func main() { 206 | // add your function calls here 207 | } 208 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Hello! Thank you for choosing to help contribute to one of the Twilio SendGrid open-source libraries. There are many ways you can contribute and help is always welcome. We simply ask that you follow the following contribution policies. 2 | 3 | All third-party contributors acknowledge that any contributions they provide will be made under the same open-source license that the open-source project is provided under. 4 | 5 | - [Improvements to the Codebase](#improvements-to-the-codebase) 6 | - [Understanding the Code Base](#understanding-the-codebase) 7 | - [Testing](#testing) 8 | - [Style Guidelines & Naming Conventions](#style-guidelines-and-naming-conventions) 9 | - [Creating a Pull Request](#creating-a-pull-request) 10 | - [Code Reviews](#code-reviews) 11 | 12 | There are a few ways to contribute, which we'll enumerate below: 13 | 14 | 15 | ## Improvements to the Codebase 16 | 17 | We welcome direct contributions to the sendgrid-go code base. Thank you! 18 | 19 | ### Development Environment ### 20 | 21 | #### Install and Run Locally #### 22 | 23 | ##### Prerequisites ##### 24 | 25 | - Go version 1.14, 1.15 or 1.16 26 | - [rest](https://github.com/sendgrid/rest) 27 | 28 | ##### Initial setup: ##### 29 | 30 | ```bash 31 | git clone https://github.com/sendgrid/sendgrid-go.git 32 | cd sendgrid-go 33 | ``` 34 | 35 | ### Environment Variables 36 | 37 | First, get your free Twilio SendGrid account [here](https://sendgrid.com/free?source=sendgrid-go). 38 | 39 | Next, update your environment with your [SENDGRID_API_KEY](https://app.sendgrid.com/settings/api_keys). 40 | 41 | ```bash 42 | echo "export SENDGRID_API_KEY='YOUR_API_KEY'" > sendgrid.env 43 | echo "sendgrid.env" >> .gitignore 44 | source ./sendgrid.env 45 | ``` 46 | 47 | ##### Execute: ##### 48 | 49 | * Check out the documentation for [Web API v3 endpoints](https://sendgrid.com/docs/API_Reference/Web_API_v3/index.html). 50 | * Review the corresponding [example](examples). 51 | * Update the file 52 | 53 | ```bash 54 | go run 55 | ``` 56 | 57 | 58 | ## Understanding the Code Base 59 | 60 | **/examples** 61 | 62 | Working examples that demonstrate usage. 63 | 64 | **sendgrid.go** 65 | 66 | The main function that does the heavy lifting (and external entry point) is `API`. 67 | 68 | 69 | ## Testing 70 | 71 | All PRs require passing tests before the PR will be reviewed. All test files are in [`sendgrid_test.go`](sendgrid_test.go). For the purposes of contributing to this repo, please update the [`sendgrid_test.go`](sendgrid_test.go) file with unit tests as you modify the code. 72 | 73 | The integration tests require a Twilio SendGrid mock API in order to execute. We've simplified setting this up using Docker to run the tests. You will just need [Docker Desktop](https://docs.docker.com/get-docker/) and `make`. 74 | 75 | Once these are available, simply execute the Docker test target to run all tests: `make test-docker`. This command can also be used to open an interactive shell into the container where this library is installed. To start a *bash* shell for example, use this command: `command=bash make test-docker`. 76 | 77 | 78 | ## Style Guidelines & Naming Conventions 79 | 80 | Generally, we follow the style guidelines as suggested by the official language. However, we ask that you conform to the styles that already exist in the library. If you wish to deviate, please explain your reasoning. 81 | 82 | - [Go Code Review Comments](https://github.com/golang/go/wiki/CodeReviewComments) 83 | 84 | Please run your code through: 85 | 86 | - [fmt](https://blog.golang.org/go-fmt-your-code) 87 | 88 | 89 | ## Creating a Pull Request 90 | 91 | 1. [Fork](https://help.github.com/fork-a-repo/) the project, clone your fork, 92 | and configure the remotes: 93 | 94 | ```bash 95 | # Clone your fork of the repo into the current directory 96 | git clone https://github.com/sendgrid/sendgrid-go 97 | 98 | # Navigate to the newly cloned directory 99 | cd sendgrid-go 100 | 101 | # Assign the original repo to a remote called "upstream" 102 | git remote add upstream https://github.com/sendgrid/sendgrid-go 103 | ``` 104 | 105 | 2. If you cloned a while ago, get the latest changes from upstream: 106 | 107 | ```bash 108 | git checkout 109 | git pull upstream 110 | ``` 111 | 112 | 3. Create a new topic branch (off the main project development branch) to 113 | contain your feature, change, or fix: 114 | 115 | ```bash 116 | git checkout -b 117 | ``` 118 | 119 | 4. Commit your changes in logical chunks. Please adhere to these [git commit 120 | message guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) 121 | or your code is unlikely to be merged into the main project. Use Git's 122 | [interactive rebase](https://help.github.com/articles/interactive-rebase) 123 | feature to tidy up your commits before making them public. 124 | 125 | 4a. Create tests. 126 | 127 | 4b. Create or update the example code that demonstrates the functionality of this change to the code. 128 | 129 | 5. Locally merge (or rebase) the upstream development branch into your topic branch: 130 | 131 | ```bash 132 | git pull [--rebase] upstream main 133 | ``` 134 | 135 | 6. Push your topic branch up to your fork: 136 | 137 | ```bash 138 | git push origin 139 | ``` 140 | 141 | 7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) 142 | with a clear title and description against the `main` branch. All tests must be passing before we will review the PR. 143 | 144 | 145 | ## Code Reviews 146 | 147 | If you can, please look at open PRs and review them. Give feedback and help us merge these PRs much faster! If you don't know how, Github has some [great information on how to review a Pull Request](https://help.github.com/articles/about-pull-request-reviews/). 148 | -------------------------------------------------------------------------------- /examples/trackingsettings/trackingsettings.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | 8 | "github.com/sendgrid/sendgrid-go" 9 | ) 10 | 11 | // RetrieveTrackingSettings : Retrieve Tracking Settings 12 | // GET /tracking_settings 13 | func RetrieveTrackingSettings() { 14 | apiKey := os.Getenv("SENDGRID_API_KEY") 15 | host := "https://api.sendgrid.com" 16 | request := sendgrid.GetRequest(apiKey, "/v3/tracking_settings", host) 17 | request.Method = "GET" 18 | queryParams := make(map[string]string) 19 | queryParams["limit"] = "1" 20 | queryParams["offset"] = "1" 21 | request.QueryParams = queryParams 22 | response, err := sendgrid.API(request) 23 | if err != nil { 24 | log.Println(err) 25 | } else { 26 | fmt.Println(response.StatusCode) 27 | fmt.Println(response.Body) 28 | fmt.Println(response.Headers) 29 | } 30 | } 31 | 32 | // UpdateClickTrackingSettings : Update Click Tracking Settings 33 | // PATCH /tracking_settings/click 34 | func UpdateClickTrackingSettings() { 35 | apiKey := os.Getenv("SENDGRID_API_KEY") 36 | host := "https://api.sendgrid.com" 37 | request := sendgrid.GetRequest(apiKey, "/v3/tracking_settings/click", host) 38 | request.Method = "PATCH" 39 | request.Body = []byte(` { 40 | "enabled": true 41 | }`) 42 | response, err := sendgrid.API(request) 43 | if err != nil { 44 | log.Println(err) 45 | } else { 46 | fmt.Println(response.StatusCode) 47 | fmt.Println(response.Body) 48 | fmt.Println(response.Headers) 49 | } 50 | } 51 | 52 | // RetrieveClickTrackSettings : Retrieve Click Track Settings 53 | // GET /tracking_settings/click 54 | func RetrieveClickTrackSettings() { 55 | apiKey := os.Getenv("SENDGRID_API_KEY") 56 | host := "https://api.sendgrid.com" 57 | request := sendgrid.GetRequest(apiKey, "/v3/tracking_settings/click", host) 58 | request.Method = "GET" 59 | response, err := sendgrid.API(request) 60 | if err != nil { 61 | log.Println(err) 62 | } else { 63 | fmt.Println(response.StatusCode) 64 | fmt.Println(response.Body) 65 | fmt.Println(response.Headers) 66 | } 67 | } 68 | 69 | // UpdateGoogleAnalyticsSettings : Update Google Analytics Settings 70 | // PATCH /tracking_settings/google_analytics 71 | func UpdateGoogleAnalyticsSettings() { 72 | apiKey := os.Getenv("SENDGRID_API_KEY") 73 | host := "https://api.sendgrid.com" 74 | request := sendgrid.GetRequest(apiKey, "/v3/tracking_settings/google_analytics", host) 75 | request.Method = "PATCH" 76 | request.Body = []byte(` { 77 | "enabled": true, 78 | "utm_campaign": "website", 79 | "utm_content": "", 80 | "utm_medium": "email", 81 | "utm_source": "sendgrid.com", 82 | "utm_term": "" 83 | }`) 84 | response, err := sendgrid.API(request) 85 | if err != nil { 86 | log.Println(err) 87 | } else { 88 | fmt.Println(response.StatusCode) 89 | fmt.Println(response.Body) 90 | fmt.Println(response.Headers) 91 | } 92 | } 93 | 94 | // RetrieveGoogleAnalyticsSettings : Retrieve Google Analytics Settings 95 | // GET /tracking_settings/google_analytics 96 | func RetrieveGoogleAnalyticsSettings() { 97 | apiKey := os.Getenv("SENDGRID_API_KEY") 98 | host := "https://api.sendgrid.com" 99 | request := sendgrid.GetRequest(apiKey, "/v3/tracking_settings/google_analytics", host) 100 | request.Method = "GET" 101 | response, err := sendgrid.API(request) 102 | if err != nil { 103 | log.Println(err) 104 | } else { 105 | fmt.Println(response.StatusCode) 106 | fmt.Println(response.Body) 107 | fmt.Println(response.Headers) 108 | } 109 | } 110 | 111 | // UpdateOpenTrackingSettings : Update Open Tracking Settings 112 | // PATCH /tracking_settings/open 113 | func UpdateOpenTrackingSettings() { 114 | apiKey := os.Getenv("SENDGRID_API_KEY") 115 | host := "https://api.sendgrid.com" 116 | request := sendgrid.GetRequest(apiKey, "/v3/tracking_settings/open", host) 117 | request.Method = "PATCH" 118 | request.Body = []byte(` { 119 | "enabled": true 120 | }`) 121 | response, err := sendgrid.API(request) 122 | if err != nil { 123 | log.Println(err) 124 | } else { 125 | fmt.Println(response.StatusCode) 126 | fmt.Println(response.Body) 127 | fmt.Println(response.Headers) 128 | } 129 | } 130 | 131 | // GetOpenTrackingSettings : Get Open Tracking Settings 132 | // GET /tracking_settings/open 133 | func GetOpenTrackingSettings() { 134 | apiKey := os.Getenv("SENDGRID_API_KEY") 135 | host := "https://api.sendgrid.com" 136 | request := sendgrid.GetRequest(apiKey, "/v3/tracking_settings/open", host) 137 | request.Method = "GET" 138 | response, err := sendgrid.API(request) 139 | if err != nil { 140 | log.Println(err) 141 | } else { 142 | fmt.Println(response.StatusCode) 143 | fmt.Println(response.Body) 144 | fmt.Println(response.Headers) 145 | } 146 | } 147 | 148 | // UpdateSubscriptionTrackingSettings : Update Subscription Tracking Settings 149 | // PATCH /tracking_settings/subscription 150 | func UpdateSubscriptionTrackingSettings() { 151 | apiKey := os.Getenv("SENDGRID_API_KEY") 152 | host := "https://api.sendgrid.com" 153 | request := sendgrid.GetRequest(apiKey, "/v3/tracking_settings/subscription", host) 154 | request.Method = "PATCH" 155 | request.Body = []byte(` { 156 | "enabled": true, 157 | "html_content": "html content", 158 | "landing": "landing page html", 159 | "plain_content": "text content", 160 | "replace": "replacement tag", 161 | "url": "url" 162 | }`) 163 | response, err := sendgrid.API(request) 164 | if err != nil { 165 | log.Println(err) 166 | } else { 167 | fmt.Println(response.StatusCode) 168 | fmt.Println(response.Body) 169 | fmt.Println(response.Headers) 170 | } 171 | } 172 | 173 | // RetrieveSubscriptionTrackingSettings : Retrieve Subscription Tracking Settings 174 | // GET /tracking_settings/subscription 175 | func RetrieveSubscriptionTrackingSettings() { 176 | apiKey := os.Getenv("SENDGRID_API_KEY") 177 | host := "https://api.sendgrid.com" 178 | request := sendgrid.GetRequest(apiKey, "/v3/tracking_settings/subscription", host) 179 | request.Method = "GET" 180 | response, err := sendgrid.API(request) 181 | if err != nil { 182 | log.Println(err) 183 | } else { 184 | fmt.Println(response.StatusCode) 185 | fmt.Println(response.Body) 186 | fmt.Println(response.Headers) 187 | } 188 | } 189 | 190 | func main() { 191 | // add your function calls here 192 | } 193 | -------------------------------------------------------------------------------- /examples/templates/templates.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | 8 | sendgrid "github.com/sendgrid/sendgrid-go" 9 | ) 10 | 11 | // Createatransactionaltemplate : Create a transactional template. 12 | // POST /templates 13 | func Createatransactionaltemplate() { 14 | apiKey := os.Getenv("SENDGRID_API_KEY") 15 | host := "https://api.sendgrid.com" 16 | request := sendgrid.GetRequest(apiKey, "/v3/templates", host) 17 | request.Method = "POST" 18 | request.Body = []byte(` { 19 | "name": "example_name" 20 | }`) 21 | response, err := sendgrid.API(request) 22 | if err != nil { 23 | log.Println(err) 24 | } else { 25 | fmt.Println(response.StatusCode) 26 | fmt.Println(response.Body) 27 | fmt.Println(response.Headers) 28 | } 29 | } 30 | 31 | // Retrievealltransactionaltemplates : Retrieve all transactional templates (legacy & dynamic). 32 | // GET /templates 33 | func Retrievealltransactionaltemplates() { 34 | apiKey := os.Getenv("SENDGRID_API_KEY") 35 | host := "https://api.sendgrid.com" 36 | request := sendgrid.GetRequest(apiKey, "/v3/templates", host) 37 | request.Method = "GET" 38 | queryParams := make(map[string]string) 39 | queryParams["generations"] = "legacy,dynamic" 40 | request.QueryParams = queryParams 41 | response, err := sendgrid.API(request) 42 | if err != nil { 43 | log.Println(err) 44 | } else { 45 | fmt.Println(response.StatusCode) 46 | fmt.Println(response.Body) 47 | fmt.Println(response.Headers) 48 | } 49 | } 50 | 51 | // Editatransactionaltemplate : Edit a transactional template. 52 | // PATCH /templates/{template_id} 53 | func Editatransactionaltemplate() { 54 | apiKey := os.Getenv("SENDGRID_API_KEY") 55 | host := "https://api.sendgrid.com" 56 | request := sendgrid.GetRequest(apiKey, "/v3/templates/{template_id}", host) 57 | request.Method = "PATCH" 58 | request.Body = []byte(` { 59 | "name": "new_example_name" 60 | }`) 61 | response, err := sendgrid.API(request) 62 | if err != nil { 63 | log.Println(err) 64 | } else { 65 | fmt.Println(response.StatusCode) 66 | fmt.Println(response.Body) 67 | fmt.Println(response.Headers) 68 | } 69 | } 70 | 71 | // Retrieveasingletransactionaltemplate : Retrieve a single transactional template. 72 | // GET /templates/{template_id} 73 | func Retrieveasingletransactionaltemplate() { 74 | apiKey := os.Getenv("SENDGRID_API_KEY") 75 | host := "https://api.sendgrid.com" 76 | request := sendgrid.GetRequest(apiKey, "/v3/templates/{template_id}", host) 77 | request.Method = "GET" 78 | response, err := sendgrid.API(request) 79 | if err != nil { 80 | log.Println(err) 81 | } else { 82 | fmt.Println(response.StatusCode) 83 | fmt.Println(response.Body) 84 | fmt.Println(response.Headers) 85 | } 86 | } 87 | 88 | // Deleteatemplate : Delete a template. 89 | // DELETE /templates/{template_id} 90 | func Deleteatemplate() { 91 | apiKey := os.Getenv("SENDGRID_API_KEY") 92 | host := "https://api.sendgrid.com" 93 | request := sendgrid.GetRequest(apiKey, "/v3/templates/{template_id}", host) 94 | request.Method = "DELETE" 95 | response, err := sendgrid.API(request) 96 | if err != nil { 97 | log.Println(err) 98 | } else { 99 | fmt.Println(response.StatusCode) 100 | fmt.Println(response.Body) 101 | fmt.Println(response.Headers) 102 | } 103 | } 104 | 105 | // Createanewtransactionaltemplateversion : Create a new transactional template version. 106 | // POST /templates/{template_id}/versions 107 | func Createanewtransactionaltemplateversion() { 108 | apiKey := os.Getenv("SENDGRID_API_KEY") 109 | host := "https://api.sendgrid.com" 110 | request := sendgrid.GetRequest(apiKey, "/v3/templates/{template_id}/versions", host) 111 | request.Method = "POST" 112 | request.Body = []byte(` { 113 | "active": 1, 114 | "html_content": "<%body%>", 115 | "name": "example_version_name", 116 | "plain_content": "<%body%>", 117 | "subject": "<%subject%>", 118 | "template_id": "ddb96bbc-9b92-425e-8979-99464621b543" 119 | }`) 120 | response, err := sendgrid.API(request) 121 | if err != nil { 122 | log.Println(err) 123 | } else { 124 | fmt.Println(response.StatusCode) 125 | fmt.Println(response.Body) 126 | fmt.Println(response.Headers) 127 | } 128 | } 129 | 130 | // Editatransactionaltemplateversion : Edit a transactional template version. 131 | // PATCH /templates/{template_id}/versions/{version_id} 132 | func Editatransactionaltemplateversion() { 133 | apiKey := os.Getenv("SENDGRID_API_KEY") 134 | host := "https://api.sendgrid.com" 135 | request := sendgrid.GetRequest(apiKey, "/v3/templates/{template_id}/versions/{version_id}", host) 136 | request.Method = "PATCH" 137 | request.Body = []byte(` { 138 | "active": 1, 139 | "html_content": "<%body%>", 140 | "name": "updated_example_name", 141 | "plain_content": "<%body%>", 142 | "subject": "<%subject%>" 143 | }`) 144 | response, err := sendgrid.API(request) 145 | if err != nil { 146 | log.Println(err) 147 | } else { 148 | fmt.Println(response.StatusCode) 149 | fmt.Println(response.Body) 150 | fmt.Println(response.Headers) 151 | } 152 | } 153 | 154 | // Retrieveaspecifictransactionaltemplateversion : Retrieve a specific transactional template version. 155 | // GET /templates/{template_id}/versions/{version_id} 156 | func Retrieveaspecifictransactionaltemplateversion() { 157 | apiKey := os.Getenv("SENDGRID_API_KEY") 158 | host := "https://api.sendgrid.com" 159 | request := sendgrid.GetRequest(apiKey, "/v3/templates/{template_id}/versions/{version_id}", host) 160 | request.Method = "GET" 161 | response, err := sendgrid.API(request) 162 | if err != nil { 163 | log.Println(err) 164 | } else { 165 | fmt.Println(response.StatusCode) 166 | fmt.Println(response.Body) 167 | fmt.Println(response.Headers) 168 | } 169 | } 170 | 171 | // Deleteatransactionaltemplateversion : Delete a transactional template version. 172 | // DELETE /templates/{template_id}/versions/{version_id} 173 | func Deleteatransactionaltemplateversion() { 174 | apiKey := os.Getenv("SENDGRID_API_KEY") 175 | host := "https://api.sendgrid.com" 176 | request := sendgrid.GetRequest(apiKey, "/v3/templates/{template_id}/versions/{version_id}", host) 177 | request.Method = "DELETE" 178 | response, err := sendgrid.API(request) 179 | if err != nil { 180 | log.Println(err) 181 | } else { 182 | fmt.Println(response.StatusCode) 183 | fmt.Println(response.Body) 184 | fmt.Println(response.Headers) 185 | } 186 | } 187 | 188 | // Activateatransactionaltemplateversion : Activate a transactional template version. 189 | // POST /templates/{template_id}/versions/{version_id}/activate 190 | func Activateatransactionaltemplateversion() { 191 | apiKey := os.Getenv("SENDGRID_API_KEY") 192 | host := "https://api.sendgrid.com" 193 | request := sendgrid.GetRequest(apiKey, "/v3/templates/{template_id}/versions/{version_id}/activate", host) 194 | request.Method = "POST" 195 | response, err := sendgrid.API(request) 196 | if err != nil { 197 | log.Println(err) 198 | } else { 199 | fmt.Println(response.StatusCode) 200 | fmt.Println(response.Body) 201 | fmt.Println(response.Headers) 202 | } 203 | } 204 | 205 | func main() { 206 | // add your function calls here 207 | } 208 | -------------------------------------------------------------------------------- /examples/campaigns/campaigns.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | 8 | sendgrid "github.com/sendgrid/sendgrid-go" 9 | ) 10 | 11 | // CreateaCampaign : Create a Campaign 12 | // POST /campaigns 13 | func CreateaCampaign() { 14 | apiKey := os.Getenv("SENDGRID_API_KEY") 15 | host := "https://api.sendgrid.com" 16 | request := sendgrid.GetRequest(apiKey, "/v3/campaigns", host) 17 | request.Method = "POST" 18 | request.Body = []byte(` { 19 | "categories": [ 20 | "spring line" 21 | ], 22 | "custom_unsubscribe_url": "", 23 | "html_content": "

Check out our spring line!

", 24 | "ip_pool": "marketing", 25 | "list_ids": [ 26 | 110, 27 | 124 28 | ], 29 | "plain_content": "Check out our spring line!", 30 | "segment_ids": [ 31 | 110 32 | ], 33 | "sender_id": 124451, 34 | "subject": "New Products for Spring!", 35 | "suppression_group_id": 42, 36 | "title": "March Newsletter" 37 | }`) 38 | response, err := sendgrid.API(request) 39 | if err != nil { 40 | log.Println(err) 41 | } else { 42 | fmt.Println(response.StatusCode) 43 | fmt.Println(response.Body) 44 | fmt.Println(response.Headers) 45 | } 46 | } 47 | 48 | // RetrieveallCampaigns : Retrieve all Campaigns 49 | // GET /campaigns 50 | func RetrieveallCampaigns() { 51 | apiKey := os.Getenv("SENDGRID_API_KEY") 52 | host := "https://api.sendgrid.com" 53 | request := sendgrid.GetRequest(apiKey, "/v3/campaigns", host) 54 | request.Method = "GET" 55 | queryParams := make(map[string]string) 56 | queryParams["limit"] = "1" 57 | queryParams["offset"] = "1" 58 | request.QueryParams = queryParams 59 | response, err := sendgrid.API(request) 60 | if err != nil { 61 | log.Println(err) 62 | } else { 63 | fmt.Println(response.StatusCode) 64 | fmt.Println(response.Body) 65 | fmt.Println(response.Headers) 66 | } 67 | } 68 | 69 | // UpdateaCampaign : Update a Campaign 70 | // PATCH /campaigns/{campaign_id} 71 | func UpdateaCampaign() { 72 | apiKey := os.Getenv("SENDGRID_API_KEY") 73 | host := "https://api.sendgrid.com" 74 | request := sendgrid.GetRequest(apiKey, "/v3/campaigns/{campaign_id}", host) 75 | request.Method = "PATCH" 76 | request.Body = []byte(` { 77 | "categories": [ 78 | "summer line" 79 | ], 80 | "html_content": "

Check out our summer line!

", 81 | "plain_content": "Check out our summer line!", 82 | "subject": "New Products for Summer!", 83 | "title": "May Newsletter" 84 | }`) 85 | response, err := sendgrid.API(request) 86 | if err != nil { 87 | log.Println(err) 88 | } else { 89 | fmt.Println(response.StatusCode) 90 | fmt.Println(response.Body) 91 | fmt.Println(response.Headers) 92 | } 93 | } 94 | 95 | // Retrieveasinglecampaign : Retrieve a single campaign 96 | // GET /campaigns/{campaign_id} 97 | func Retrieveasinglecampaign() { 98 | apiKey := os.Getenv("SENDGRID_API_KEY") 99 | host := "https://api.sendgrid.com" 100 | request := sendgrid.GetRequest(apiKey, "/v3/campaigns/{campaign_id}", host) 101 | request.Method = "GET" 102 | response, err := sendgrid.API(request) 103 | if err != nil { 104 | log.Println(err) 105 | } else { 106 | fmt.Println(response.StatusCode) 107 | fmt.Println(response.Body) 108 | fmt.Println(response.Headers) 109 | } 110 | } 111 | 112 | // DeleteaCampaign : Delete a Campaign 113 | // DELETE /campaigns/{campaign_id} 114 | func DeleteaCampaign() { 115 | apiKey := os.Getenv("SENDGRID_API_KEY") 116 | host := "https://api.sendgrid.com" 117 | request := sendgrid.GetRequest(apiKey, "/v3/campaigns/{campaign_id}", host) 118 | request.Method = "DELETE" 119 | response, err := sendgrid.API(request) 120 | if err != nil { 121 | log.Println(err) 122 | } else { 123 | fmt.Println(response.StatusCode) 124 | fmt.Println(response.Body) 125 | fmt.Println(response.Headers) 126 | } 127 | } 128 | 129 | // UpdateaScheduledCampaign : Update a Scheduled Campaign 130 | // PATCH /campaigns/{campaign_id}/schedules 131 | func UpdateaScheduledCampaign() { 132 | apiKey := os.Getenv("SENDGRID_API_KEY") 133 | host := "https://api.sendgrid.com" 134 | request := sendgrid.GetRequest(apiKey, "/v3/campaigns/{campaign_id}/schedules", host) 135 | request.Method = "PATCH" 136 | request.Body = []byte(` { 137 | "send_at": 1489451436 138 | }`) 139 | response, err := sendgrid.API(request) 140 | if err != nil { 141 | log.Println(err) 142 | } else { 143 | fmt.Println(response.StatusCode) 144 | fmt.Println(response.Body) 145 | fmt.Println(response.Headers) 146 | } 147 | } 148 | 149 | // ScheduleaCampaign : Schedule a Campaign 150 | // POST /campaigns/{campaign_id}/schedules 151 | func ScheduleaCampaign() { 152 | apiKey := os.Getenv("SENDGRID_API_KEY") 153 | host := "https://api.sendgrid.com" 154 | request := sendgrid.GetRequest(apiKey, "/v3/campaigns/{campaign_id}/schedules", host) 155 | request.Method = "POST" 156 | request.Body = []byte(` { 157 | "send_at": 1489771528 158 | }`) 159 | response, err := sendgrid.API(request) 160 | if err != nil { 161 | log.Println(err) 162 | } else { 163 | fmt.Println(response.StatusCode) 164 | fmt.Println(response.Body) 165 | fmt.Println(response.Headers) 166 | } 167 | } 168 | 169 | // ViewScheduledTimeofaCampaign : View Scheduled Time of a Campaign 170 | // GET /campaigns/{campaign_id}/schedules 171 | func ViewScheduledTimeofaCampaign() { 172 | apiKey := os.Getenv("SENDGRID_API_KEY") 173 | host := "https://api.sendgrid.com" 174 | request := sendgrid.GetRequest(apiKey, "/v3/campaigns/{campaign_id}/schedules", host) 175 | request.Method = "GET" 176 | response, err := sendgrid.API(request) 177 | if err != nil { 178 | log.Println(err) 179 | } else { 180 | fmt.Println(response.StatusCode) 181 | fmt.Println(response.Body) 182 | fmt.Println(response.Headers) 183 | } 184 | } 185 | 186 | // UnscheduleaScheduledCampaign : Unschedule a Scheduled Campaign 187 | // DELETE /campaigns/{campaign_id}/schedules 188 | func UnscheduleaScheduledCampaign() { 189 | apiKey := os.Getenv("SENDGRID_API_KEY") 190 | host := "https://api.sendgrid.com" 191 | request := sendgrid.GetRequest(apiKey, "/v3/campaigns/{campaign_id}/schedules", host) 192 | request.Method = "DELETE" 193 | response, err := sendgrid.API(request) 194 | if err != nil { 195 | log.Println(err) 196 | } else { 197 | fmt.Println(response.StatusCode) 198 | fmt.Println(response.Body) 199 | fmt.Println(response.Headers) 200 | } 201 | } 202 | 203 | // SendaCampaign : Send a Campaign 204 | // POST /campaigns/{campaign_id}/schedules/now 205 | func SendaCampaign() { 206 | apiKey := os.Getenv("SENDGRID_API_KEY") 207 | host := "https://api.sendgrid.com" 208 | request := sendgrid.GetRequest(apiKey, "/v3/campaigns/{campaign_id}/schedules/now", host) 209 | request.Method = "POST" 210 | response, err := sendgrid.API(request) 211 | if err != nil { 212 | log.Println(err) 213 | } else { 214 | fmt.Println(response.StatusCode) 215 | fmt.Println(response.Body) 216 | fmt.Println(response.Headers) 217 | } 218 | } 219 | 220 | // SendaTestCampaign : Send a Test Campaign 221 | // POST /campaigns/{campaign_id}/schedules/test 222 | func SendaTestCampaign() { 223 | apiKey := os.Getenv("SENDGRID_API_KEY") 224 | host := "https://api.sendgrid.com" 225 | request := sendgrid.GetRequest(apiKey, "/v3/campaigns/{campaign_id}/schedules/test", host) 226 | request.Method = "POST" 227 | request.Body = []byte(` { 228 | "to": "your.email@example.com" 229 | }`) 230 | response, err := sendgrid.API(request) 231 | if err != nil { 232 | log.Println(err) 233 | } else { 234 | fmt.Println(response.StatusCode) 235 | fmt.Println(response.Body) 236 | fmt.Println(response.Headers) 237 | } 238 | } 239 | 240 | func main() { 241 | // add your function calls here 242 | } 243 | -------------------------------------------------------------------------------- /helpers/inbound/inbound.go: -------------------------------------------------------------------------------- 1 | package inbound 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io" 7 | "mime" 8 | "mime/multipart" 9 | "net/http" 10 | "strings" 11 | ) 12 | 13 | // ParsedEmail defines a multipart parsed email 14 | // Body and Attachments are only populated if the Raw option is checked on the SendGrid inbound configuration and are named for backwards compatability 15 | type ParsedEmail struct { 16 | // Header values are raw and not pre-processed by SendGrid. They may change depending on the email client. Use carefully 17 | Headers map[string]string 18 | // Please see https://docs.sendgrid.com/for-developers/parsing-email/setting-up-the-inbound-parse-webhook to see the available fields in the email headers 19 | // all fields listed there are available within the headers map except for text which lives in the TextBody field 20 | ParsedValues map[string]string 21 | // Primary email body parsed with \n. A common approach is to Split by the \n to bring every line of the email into a string array 22 | TextBody string 23 | 24 | // Envelope expresses the exact email address that the email was addressed to and the exact email address it was from, without extra characters 25 | Envelope struct { 26 | From string `json:"from"` 27 | To []string `json:"to"` 28 | } 29 | 30 | // Attachments have been fully parsed to include the filename, size, content type and actual file for uploading or processing 31 | ParsedAttachments map[string]*EmailAttachment 32 | 33 | // Raw only 34 | Attachments map[string][]byte 35 | // accessed with text/html and text/plain. text/plain is always parsed to the TextBody field 36 | Body map[string]string 37 | 38 | rawRequest *http.Request 39 | rawValues map[string][]string 40 | withAttachments bool 41 | } 42 | 43 | // EmailAttachment defines information related to an email attachment 44 | type EmailAttachment struct { 45 | File multipart.File `json:"-"` 46 | Filename string `json:"filename"` 47 | Size int64 `json:"-"` 48 | ContentType string `json:"type"` 49 | } 50 | 51 | func newParsedEmail(request *http.Request) ParsedEmail { 52 | return ParsedEmail{ 53 | Headers: make(map[string]string), 54 | ParsedValues: make(map[string]string), 55 | ParsedAttachments: make(map[string]*EmailAttachment), 56 | 57 | Body: make(map[string]string), 58 | Attachments: make(map[string][]byte), 59 | 60 | rawRequest: request, 61 | withAttachments: false, 62 | } 63 | } 64 | 65 | // Parse parses an email using Go's multipart parser and populates the headers, and body 66 | // This method skips processing the attachment file and is therefore more performant 67 | func Parse(request *http.Request) (*ParsedEmail, error) { 68 | result := newParsedEmail(request) 69 | 70 | err := result.parse() 71 | return &result, err 72 | } 73 | 74 | // ParseWithAttachments parses an email using Go's multipart parser and populates the headers, body and processes attachments 75 | func ParseWithAttachments(request *http.Request) (*ParsedEmail, error) { 76 | result := newParsedEmail(request) 77 | result.withAttachments = true 78 | 79 | err := result.parse() 80 | return &result, err 81 | } 82 | 83 | func (email *ParsedEmail) parse() error { 84 | err := email.rawRequest.ParseMultipartForm(0) 85 | if err != nil { 86 | return err 87 | } 88 | 89 | email.rawValues = email.rawRequest.MultipartForm.Value 90 | 91 | // unmarshal the envelope 92 | if len(email.rawValues["envelope"]) > 0 { 93 | if err := json.Unmarshal([]byte(email.rawValues["envelope"][0]), &email.Envelope); err != nil { 94 | return err 95 | } 96 | } 97 | 98 | // parse included headers 99 | if len(email.rawValues["headers"]) > 0 { 100 | email.parseHeaders(email.rawValues["headers"][0]) 101 | } 102 | 103 | // apply the rest of the SendGrid fields to the headers map 104 | for k, v := range email.rawValues { 105 | if k == "text" || k == "email" || k == "headers" || k == "envelope" { 106 | continue 107 | } 108 | 109 | if len(v) > 0 { 110 | email.ParsedValues[k] = v[0] 111 | } 112 | } 113 | 114 | // apply the plain text body 115 | if len(email.rawValues["text"]) > 0 { 116 | email.TextBody = email.rawValues["text"][0] 117 | } 118 | 119 | // only included if the raw box is checked 120 | if len(email.rawValues["email"]) > 0 { 121 | email.parseRawEmail(email.rawValues["email"][0]) 122 | } 123 | 124 | // if the client chose not to parse attachments, return as is 125 | if !email.withAttachments { 126 | return nil 127 | } 128 | 129 | return email.parseAttachments(email.rawValues) 130 | } 131 | 132 | func (email *ParsedEmail) parseAttachments(values map[string][]string) error { 133 | if len(values["attachment-info"]) != 1 { 134 | return nil 135 | } 136 | // unmarshal the sendgrid parsed aspects of the email attachment into the attachment struct 137 | if err := json.Unmarshal([]byte(values["attachment-info"][0]), &email.ParsedAttachments); err != nil { 138 | return err 139 | } 140 | 141 | // range through the multipart files 142 | for key, val := range email.rawRequest.MultipartForm.File { 143 | // open the attachment file for processing 144 | file, err := val[0].Open() 145 | if err != nil { 146 | return err 147 | } 148 | 149 | // add the actual file and the size to the parsed files 150 | email.ParsedAttachments[key].File = file 151 | email.ParsedAttachments[key].Size = val[0].Size 152 | 153 | // if the file does not have a name. give it Untitled 154 | if email.ParsedAttachments[key].Filename == "" { 155 | email.ParsedAttachments[key].Filename = "Untitled" 156 | } 157 | } 158 | 159 | return nil 160 | } 161 | 162 | func (email *ParsedEmail) parseRawEmail(rawEmail string) error { 163 | sections := strings.SplitN(rawEmail, "\n\n", 2) 164 | email.parseHeaders(sections[0]) 165 | raw, err := parseMultipart(strings.NewReader(sections[1]), email.Headers["Content-Type"]) 166 | if err != nil { 167 | return err 168 | } 169 | 170 | for { 171 | emailPart, err := raw.NextPart() 172 | if err == io.EOF { 173 | return nil 174 | } 175 | rawEmailBody, err := parseMultipart(emailPart, emailPart.Header.Get("Content-Type")) 176 | if err != nil { 177 | return err 178 | } 179 | if rawEmailBody != nil { 180 | for { 181 | emailBodyPart, err := rawEmailBody.NextPart() 182 | if err == io.EOF { 183 | break 184 | } 185 | header := emailBodyPart.Header.Get("Content-Type") 186 | b, err := io.ReadAll(emailPart) 187 | if err != nil { 188 | return err 189 | } 190 | email.Body[header] = string(b) 191 | } 192 | 193 | } else if emailPart.FileName() != "" { 194 | b, err := io.ReadAll(emailPart) 195 | if err != nil { 196 | return err 197 | } 198 | email.Attachments[emailPart.FileName()] = b 199 | } else { 200 | header := emailPart.Header.Get("Content-Type") 201 | b, err := io.ReadAll(emailPart) 202 | if err != nil { 203 | return err 204 | } 205 | 206 | email.Body[header] = string(b) 207 | } 208 | } 209 | } 210 | 211 | func parseMultipart(body io.Reader, contentType string) (*multipart.Reader, error) { 212 | mediaType, params, err := mime.ParseMediaType(contentType) 213 | if err != nil { 214 | return nil, err 215 | } 216 | 217 | if strings.HasPrefix(mediaType, "multipart/") { 218 | return multipart.NewReader(body, params["boundary"]), nil 219 | } 220 | return nil, nil 221 | } 222 | 223 | func (email *ParsedEmail) parseHeaders(headers string) { 224 | splitHeaders := strings.Split(strings.TrimSpace(headers), "\n") 225 | for _, header := range splitHeaders { 226 | splitHeader := strings.SplitN(header, ": ", 2) 227 | // keeps outlook emails from causing a panic 228 | if len(splitHeader) != 2 { 229 | continue 230 | } 231 | 232 | email.Headers[splitHeader[0]] = splitHeader[1] 233 | } 234 | } 235 | 236 | // Validate validates the DKIM and SPF scores to ensure that the email client and address was not spoofed 237 | func (email *ParsedEmail) Validate() error { 238 | if len(email.rawValues["dkim"]) == 0 || len(email.rawValues["SPF"]) == 0 { 239 | return fmt.Errorf("missing DKIM and SPF score") 240 | } 241 | 242 | for _, val := range email.rawValues["dkim"] { 243 | if !strings.Contains(val, "pass") { 244 | return fmt.Errorf("DKIM validation failed") 245 | } 246 | } 247 | 248 | for _, val := range email.rawValues["SPF"] { 249 | if !strings.Contains(val, "pass") { 250 | return fmt.Errorf("SPF validation failed") 251 | } 252 | } 253 | 254 | return nil 255 | } 256 | -------------------------------------------------------------------------------- /examples/ips/ips.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | 8 | "github.com/sendgrid/sendgrid-go" 9 | ) 10 | 11 | // RetrieveallIPaddresses : Retrieve all IP addresses 12 | // GET /ips 13 | func RetrieveallIPaddresses() { 14 | apiKey := os.Getenv("SENDGRID_API_KEY") 15 | host := "https://api.sendgrid.com" 16 | request := sendgrid.GetRequest(apiKey, "/v3/ips", host) 17 | request.Method = "GET" 18 | queryParams := make(map[string]string) 19 | queryParams["subuser"] = "test_string" 20 | queryParams["ip"] = "test_string" 21 | queryParams["limit"] = "1" 22 | queryParams["exclude_whitelabels"] = "true" 23 | queryParams["offset"] = "1" 24 | request.QueryParams = queryParams 25 | response, err := sendgrid.API(request) 26 | if err != nil { 27 | log.Println(err) 28 | } else { 29 | fmt.Println(response.StatusCode) 30 | fmt.Println(response.Body) 31 | fmt.Println(response.Headers) 32 | } 33 | } 34 | 35 | // RetrieveallassignedIPs : Retrieve all assigned IPs 36 | // GET /ips/assigned 37 | func RetrieveallassignedIPs() { 38 | apiKey := os.Getenv("SENDGRID_API_KEY") 39 | host := "https://api.sendgrid.com" 40 | request := sendgrid.GetRequest(apiKey, "/v3/ips/assigned", host) 41 | request.Method = "GET" 42 | response, err := sendgrid.API(request) 43 | if err != nil { 44 | log.Println(err) 45 | } else { 46 | fmt.Println(response.StatusCode) 47 | fmt.Println(response.Body) 48 | fmt.Println(response.Headers) 49 | } 50 | } 51 | 52 | // CreateanIPpool : Create an IP pool. 53 | // POST /ips/pools 54 | func CreateanIPpool() { 55 | apiKey := os.Getenv("SENDGRID_API_KEY") 56 | host := "https://api.sendgrid.com" 57 | request := sendgrid.GetRequest(apiKey, "/v3/ips/pools", host) 58 | request.Method = "POST" 59 | request.Body = []byte(` { 60 | "name": "marketing" 61 | }`) 62 | response, err := sendgrid.API(request) 63 | if err != nil { 64 | log.Println(err) 65 | } else { 66 | fmt.Println(response.StatusCode) 67 | fmt.Println(response.Body) 68 | fmt.Println(response.Headers) 69 | } 70 | } 71 | 72 | // RetrieveallIPpools : Retrieve all IP pools. 73 | // GET /ips/pools 74 | func RetrieveallIPpools() { 75 | apiKey := os.Getenv("SENDGRID_API_KEY") 76 | host := "https://api.sendgrid.com" 77 | request := sendgrid.GetRequest(apiKey, "/v3/ips/pools", host) 78 | request.Method = "GET" 79 | response, err := sendgrid.API(request) 80 | if err != nil { 81 | log.Println(err) 82 | } else { 83 | fmt.Println(response.StatusCode) 84 | fmt.Println(response.Body) 85 | fmt.Println(response.Headers) 86 | } 87 | } 88 | 89 | // UpdateanIPpoolsname : Update an IP pools name. 90 | // PUT /ips/pools/{pool_name} 91 | func UpdateanIPpoolsname() { 92 | apiKey := os.Getenv("SENDGRID_API_KEY") 93 | host := "https://api.sendgrid.com" 94 | request := sendgrid.GetRequest(apiKey, "/v3/ips/pools/{pool_name}", host) 95 | request.Method = "PUT" 96 | request.Body = []byte(` { 97 | "name": "new_pool_name" 98 | }`) 99 | response, err := sendgrid.API(request) 100 | if err != nil { 101 | log.Println(err) 102 | } else { 103 | fmt.Println(response.StatusCode) 104 | fmt.Println(response.Body) 105 | fmt.Println(response.Headers) 106 | } 107 | } 108 | 109 | // RetrieveallIPsinaspecifiedpool : Retrieve all IPs in a specified pool. 110 | // GET /ips/pools/{pool_name} 111 | func RetrieveallIPsinaspecifiedpool() { 112 | apiKey := os.Getenv("SENDGRID_API_KEY") 113 | host := "https://api.sendgrid.com" 114 | request := sendgrid.GetRequest(apiKey, "/v3/ips/pools/{pool_name}", host) 115 | request.Method = "GET" 116 | response, err := sendgrid.API(request) 117 | if err != nil { 118 | log.Println(err) 119 | } else { 120 | fmt.Println(response.StatusCode) 121 | fmt.Println(response.Body) 122 | fmt.Println(response.Headers) 123 | } 124 | } 125 | 126 | // DeleteanIPpool : Delete an IP pool. 127 | // DELETE /ips/pools/{pool_name} 128 | func DeleteanIPpool() { 129 | apiKey := os.Getenv("SENDGRID_API_KEY") 130 | host := "https://api.sendgrid.com" 131 | request := sendgrid.GetRequest(apiKey, "/v3/ips/pools/{pool_name}", host) 132 | request.Method = "DELETE" 133 | response, err := sendgrid.API(request) 134 | if err != nil { 135 | log.Println(err) 136 | } else { 137 | fmt.Println(response.StatusCode) 138 | fmt.Println(response.Body) 139 | fmt.Println(response.Headers) 140 | } 141 | } 142 | 143 | // AddanIPaddresstoapool : Add an IP address to a pool 144 | // POST /ips/pools/{pool_name}/ips 145 | func AddanIPaddresstoapool() { 146 | apiKey := os.Getenv("SENDGRID_API_KEY") 147 | host := "https://api.sendgrid.com" 148 | request := sendgrid.GetRequest(apiKey, "/v3/ips/pools/{pool_name}/ips", host) 149 | request.Method = "POST" 150 | request.Body = []byte(` { 151 | "ip": "0.0.0.0" 152 | }`) 153 | response, err := sendgrid.API(request) 154 | if err != nil { 155 | log.Println(err) 156 | } else { 157 | fmt.Println(response.StatusCode) 158 | fmt.Println(response.Body) 159 | fmt.Println(response.Headers) 160 | } 161 | } 162 | 163 | // RemoveanIPaddressfromapool : Remove an IP address from a pool. 164 | // DELETE /ips/pools/{pool_name}/ips/{ip} 165 | func RemoveanIPaddressfromapool() { 166 | apiKey := os.Getenv("SENDGRID_API_KEY") 167 | host := "https://api.sendgrid.com" 168 | request := sendgrid.GetRequest(apiKey, "/v3/ips/pools/{pool_name}/ips/{ip}", host) 169 | request.Method = "DELETE" 170 | response, err := sendgrid.API(request) 171 | if err != nil { 172 | log.Println(err) 173 | } else { 174 | fmt.Println(response.StatusCode) 175 | fmt.Println(response.Body) 176 | fmt.Println(response.Headers) 177 | } 178 | } 179 | 180 | // AddanIPtowarmup : Add an IP to warmup 181 | // POST /ips/warmup 182 | func AddanIPtowarmup() { 183 | apiKey := os.Getenv("SENDGRID_API_KEY") 184 | host := "https://api.sendgrid.com" 185 | request := sendgrid.GetRequest(apiKey, "/v3/ips/warmup", host) 186 | request.Method = "POST" 187 | request.Body = []byte(` { 188 | "ip": "0.0.0.0" 189 | }`) 190 | response, err := sendgrid.API(request) 191 | if err != nil { 192 | log.Println(err) 193 | } else { 194 | fmt.Println(response.StatusCode) 195 | fmt.Println(response.Body) 196 | fmt.Println(response.Headers) 197 | } 198 | } 199 | 200 | // RetrieveallIPscurrentlyinwarmup : Retrieve all IPs currently in warmup 201 | // GET /ips/warmup 202 | func RetrieveallIPscurrentlyinwarmup() { 203 | apiKey := os.Getenv("SENDGRID_API_KEY") 204 | host := "https://api.sendgrid.com" 205 | request := sendgrid.GetRequest(apiKey, "/v3/ips/warmup", host) 206 | request.Method = "GET" 207 | response, err := sendgrid.API(request) 208 | if err != nil { 209 | log.Println(err) 210 | } else { 211 | fmt.Println(response.StatusCode) 212 | fmt.Println(response.Body) 213 | fmt.Println(response.Headers) 214 | } 215 | } 216 | 217 | // RetrievewarmupstatusforaspecificIPaddress : Retrieve warmup status for a specific IP address 218 | // GET /ips/warmup/{ip_address} 219 | func RetrievewarmupstatusforaspecificIPaddress() { 220 | apiKey := os.Getenv("SENDGRID_API_KEY") 221 | host := "https://api.sendgrid.com" 222 | request := sendgrid.GetRequest(apiKey, "/v3/ips/warmup/{ip_address}", host) 223 | request.Method = "GET" 224 | response, err := sendgrid.API(request) 225 | if err != nil { 226 | log.Println(err) 227 | } else { 228 | fmt.Println(response.StatusCode) 229 | fmt.Println(response.Body) 230 | fmt.Println(response.Headers) 231 | } 232 | } 233 | 234 | // RemoveanIPfromwarmup : Remove an IP from warmup 235 | // DELETE /ips/warmup/{ip_address} 236 | func RemoveanIPfromwarmup() { 237 | apiKey := os.Getenv("SENDGRID_API_KEY") 238 | host := "https://api.sendgrid.com" 239 | request := sendgrid.GetRequest(apiKey, "/v3/ips/warmup/{ip_address}", host) 240 | request.Method = "DELETE" 241 | response, err := sendgrid.API(request) 242 | if err != nil { 243 | log.Println(err) 244 | } else { 245 | fmt.Println(response.StatusCode) 246 | fmt.Println(response.Body) 247 | fmt.Println(response.Headers) 248 | } 249 | } 250 | 251 | // RetrieveallIPpoolsanIPaddressbelongsto : Retrieve all IP pools an IP address belongs to 252 | // GET /ips/{ip_address} 253 | func RetrieveallIPpoolsanIPaddressbelongsto() { 254 | apiKey := os.Getenv("SENDGRID_API_KEY") 255 | host := "https://api.sendgrid.com" 256 | request := sendgrid.GetRequest(apiKey, "/v3/ips/{ip_address}", host) 257 | request.Method = "GET" 258 | response, err := sendgrid.API(request) 259 | if err != nil { 260 | log.Println(err) 261 | } else { 262 | fmt.Println(response.StatusCode) 263 | fmt.Println(response.Body) 264 | fmt.Println(response.Headers) 265 | } 266 | } 267 | 268 | func main() { 269 | // add your function calls here 270 | } 271 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Twilio SendGrid Logo](twilio_sendgrid_logo.png) 2 | 3 | [![Test and Deploy](https://github.com/sendgrid/sendgrid-go/actions/workflows/test-and-deploy.yml/badge.svg)](https://github.com/sendgrid/sendgrid-go/actions/workflows/test-and-deploy.yml) 4 | [![GoDoc](https://godoc.org/github.com/sendgrid/sendgrid-go?status.svg)](https://godoc.org/github.com/sendgrid/sendgrid-go) 5 | [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) 6 | [![Twitter Follow](https://img.shields.io/twitter/follow/sendgrid.svg?style=social&label=Follow)](https://twitter.com/sendgrid) 7 | [![GitHub contributors](https://img.shields.io/github/contributors/sendgrid/sendgrid-go.svg)](https://github.com/sendgrid/sendgrid-go/graphs/contributors) 8 | [![Open Source Helpers](https://www.codetriage.com/sendgrid/sendgrid-go/badges/users.svg)](https://www.codetriage.com/sendgrid/sendgrid-go) 9 | 10 | **This library allows you to quickly and easily use the Twilio SendGrid Web API v3 via Go.** 11 | 12 | Version 3.X.X of this library provides full support for all Twilio SendGrid [Web API v3](https://sendgrid.com/docs/API_Reference/Web_API_v3/index.html) endpoints, including the new [v3 /mail/send](https://sendgrid.com/blog/introducing-v3mailsend-sendgrids-new-mail-endpoint). 13 | 14 | This library represents the beginning of a new path for Twilio SendGrid. We want this library to be community driven and Twilio SendGrid led. We need your help to realize this goal. To help make sure we are building the right things in the right order, we ask that you create [issues](https://github.com/sendgrid/sendgrid-go/issues) and [pull requests](CONTRIBUTING.md) or simply upvote or comment on existing issues or pull requests. 15 | 16 | **If you need help using SendGrid, please check the [Twilio SendGrid Support Help Center](https://support.sendgrid.com).** 17 | 18 | # Table of Contents 19 | 20 | * [Installation](#installation) 21 | * [Quick Start](#quick-start) 22 | * [Processing Inbound Email](#inbound) 23 | * [Usage](#usage) 24 | * [Use Cases](#use-cases) 25 | * [Announcements](#announcements) 26 | * [How to Contribute](#contribute) 27 | * [Troubleshooting](#troubleshooting) 28 | * [About](#about) 29 | * [License](#license) 30 | 31 | 32 | # Installation 33 | 34 | ## Supported Versions 35 | 36 | This library supports the following Go implementations: 37 | 38 | * Go 1.14 39 | * Go 1.15 40 | * Go 1.16 41 | * Go 1.17 42 | * Go 1.18 43 | * Go 1.19 44 | 45 | ## Prerequisites 46 | 47 | - The Twilio SendGrid service, starting at the [free level](https://sendgrid.com/free?source=sendgrid-go), to send up to 40,000 emails for the first 30 days, then send 100 emails/day free forever or check out [our pricing](https://sendgrid.com/pricing?source=sendgrid-go). 48 | 49 | ## Setup Environment Variables 50 | 51 | Update the development environment with your [SENDGRID_API_KEY](https://app.sendgrid.com/settings/api_keys), for example: 52 | 53 | ```bash 54 | echo "export SENDGRID_API_KEY='YOUR_API_KEY'" > sendgrid.env 55 | echo "sendgrid.env" >> .gitignore 56 | source ./sendgrid.env 57 | ``` 58 | 59 | ## Install Package 60 | 61 | `go get github.com/sendgrid/sendgrid-go` 62 | 63 | ## Dependencies 64 | 65 | - [rest](https://github.com/sendgrid/rest) 66 | 67 | ## Setup Environment Variables 68 | 69 | ### Initial Setup 70 | 71 | ```bash 72 | cp .env_sample .env 73 | ``` 74 | 75 | ### Environment Variable 76 | 77 | Update the development environment with your [SENDGRID_API_KEY](https://app.sendgrid.com/settings/api_keys), for example: 78 | 79 | ```bash 80 | echo "export SENDGRID_API_KEY='YOUR_API_KEY'" > sendgrid.env 81 | echo "sendgrid.env" >> .gitignore 82 | source ./sendgrid.env 83 | ``` 84 | 85 | 86 | # Quick Start 87 | 88 | ## Hello Email 89 | 90 | The following is the minimum needed code to send an email with the [/mail/send Helper](helpers/mail) ([here](examples/helpers/mail/example.go#L32) is a full example): 91 | 92 | ### With Mail Helper Class 93 | 94 | ```go 95 | package main 96 | 97 | import ( 98 | "fmt" 99 | "log" 100 | "os" 101 | 102 | "github.com/sendgrid/sendgrid-go" 103 | "github.com/sendgrid/sendgrid-go/helpers/mail" 104 | ) 105 | 106 | func main() { 107 | from := mail.NewEmail("Example User", "test@example.com") 108 | subject := "Sending with Twilio SendGrid is Fun" 109 | to := mail.NewEmail("Example User", "test@example.com") 110 | plainTextContent := "and easy to do anywhere, even with Go" 111 | htmlContent := "and easy to do anywhere, even with Go" 112 | message := mail.NewSingleEmail(from, subject, to, plainTextContent, htmlContent) 113 | client := sendgrid.NewSendClient(os.Getenv("SENDGRID_API_KEY")) 114 | response, err := client.Send(message) 115 | if err != nil { 116 | log.Println(err) 117 | } else { 118 | fmt.Println(response.StatusCode) 119 | fmt.Println(response.Body) 120 | fmt.Println(response.Headers) 121 | } 122 | } 123 | ``` 124 | 125 | The `NewEmail` constructor creates a [personalization object](https://sendgrid.com/docs/Classroom/Send/v3_Mail_Send/personalizations.html) for you. [Here](examples/helpers/mail/example.go#L28) is an example of how to add to it. 126 | 127 | ### Without Mail Helper Class 128 | 129 | The following is the minimum needed code to send an email without the /mail/send Helper ([here](examples/mail/mail.go#L47) is a full example): 130 | 131 | ```go 132 | package main 133 | 134 | import ( 135 | "fmt" 136 | "github.com/sendgrid/sendgrid-go" 137 | "log" 138 | "os" 139 | ) 140 | 141 | func main() { 142 | request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KEY"), "/v3/mail/send", "https://api.sendgrid.com") 143 | request.Method = "POST" 144 | request.Body = []byte(` { 145 | "personalizations": [ 146 | { 147 | "to": [ 148 | { 149 | "email": "test@example.com" 150 | } 151 | ], 152 | "subject": "Sending with Twilio SendGrid is Fun" 153 | } 154 | ], 155 | "from": { 156 | "email": "test@example.com" 157 | }, 158 | "content": [ 159 | { 160 | "type": "text/plain", 161 | "value": "and easy to do anywhere, even with Go" 162 | } 163 | ] 164 | }`) 165 | response, err := sendgrid.API(request) 166 | if err != nil { 167 | log.Println(err) 168 | } else { 169 | fmt.Println(response.StatusCode) 170 | fmt.Println(response.Body) 171 | fmt.Println(response.Headers) 172 | } 173 | } 174 | ``` 175 | 176 | ## General v3 Web API Usage 177 | 178 | ```go 179 | package main 180 | 181 | import ( 182 | "fmt" 183 | "github.com/sendgrid/sendgrid-go" 184 | "log" 185 | "os" 186 | ) 187 | 188 | func main() { 189 | request := sendgrid.GetRequest(os.Getenv("SENDGRID_API_KEY"), "/v3/api_keys", "https://api.sendgrid.com") 190 | request.Method = "GET" 191 | 192 | response, err := sendgrid.API(request) 193 | if err != nil { 194 | log.Println(err) 195 | } else { 196 | fmt.Println(response.StatusCode) 197 | fmt.Println(response.Body) 198 | fmt.Println(response.Headers) 199 | } 200 | } 201 | ``` 202 | 203 | 204 | 205 | # Processing Inbound Email 206 | 207 | Please see [our helper](helpers/inbound) for utilizing our Inbound Parse webhook. 208 | 209 | 210 | # Usage 211 | 212 | - [Twilio SendGrid Docs](https://sendgrid.com/docs/API_Reference/index.html) 213 | - [Library Usage Docs](USAGE.md) 214 | - [Example Code](examples) 215 | - [How-to: Migration from v2 to v3](https://sendgrid.com/docs/Classroom/Send/v3_Mail_Send/how_to_migrate_from_v2_to_v3_mail_send.html) 216 | - [v3 Web API Mail Send Helper](helpers/mail/README.md) 217 | 218 | 219 | # Use Cases 220 | 221 | [Examples of common API use cases](use-cases/README.md), such as how to send an email with a transactional template. 222 | 223 | 224 | # Announcements 225 | 226 | All updates to this library are documented in our [CHANGELOG](CHANGELOG.md) and [releases](https://github.com/sendgrid/sendgrid-go/releases). 227 | 228 | 229 | # How to Contribute 230 | 231 | We encourage contribution to our libraries (you might even score some nifty swag), please see our [CONTRIBUTING](CONTRIBUTING.md) guide for details. 232 | 233 | Quick links: 234 | 235 | - [Feature Request](CONTRIBUTING.md#feature-request) 236 | - [Bug Reports](CONTRIBUTING.md#submit-a-bug-report) 237 | - [Improvements to the Codebase](CONTRIBUTING.md#improvements-to-the-codebase) 238 | - [Review Pull Requests](CONTRIBUTING.md#code-reviews) 239 | 240 | 241 | # Troubleshooting 242 | 243 | Please see our [troubleshooting guide](TROUBLESHOOTING.md) for common library issues. 244 | 245 | 246 | # About 247 | 248 | sendgrid-go is maintained and funded by Twilio SendGrid, Inc. The names and logos for sendgrid-go are trademarks of Twilio SendGrid, Inc. 249 | 250 | 251 | # Support 252 | 253 | If you need help using SendGrid, please check the [Twilio SendGrid Support Help Center](https://support.sendgrid.com). 254 | 255 | # License 256 | [The MIT License (MIT)](LICENSE) 257 | -------------------------------------------------------------------------------- /examples/asm/asm.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | 8 | "github.com/sendgrid/sendgrid-go" 9 | ) 10 | 11 | // Createanewsuppressiongroup : Create a new suppression group 12 | // POST /asm/groups 13 | func Createanewsuppressiongroup() { 14 | apiKey := os.Getenv("SENDGRID_API_KEY") 15 | host := "https://api.sendgrid.com" 16 | request := sendgrid.GetRequest(apiKey, "/v3/asm/groups", host) 17 | request.Method = "POST" 18 | request.Body = []byte(` { 19 | "description": "Suggestions for products our users might like.", 20 | "is_default": true, 21 | "name": "Product Suggestions" 22 | }`) 23 | response, err := sendgrid.API(request) 24 | if err != nil { 25 | log.Println(err) 26 | } else { 27 | fmt.Println(response.StatusCode) 28 | fmt.Println(response.Body) 29 | fmt.Println(response.Headers) 30 | } 31 | } 32 | 33 | // Retrieveinformationaboutmultiplesuppressiongroups : Retrieve information about multiple suppression groups 34 | // GET /asm/groups 35 | func Retrieveinformationaboutmultiplesuppressiongroups() { 36 | apiKey := os.Getenv("SENDGRID_API_KEY") 37 | host := "https://api.sendgrid.com" 38 | request := sendgrid.GetRequest(apiKey, "/v3/asm/groups", host) 39 | request.Method = "GET" 40 | queryParams := make(map[string]string) 41 | queryParams["id"] = "1" 42 | request.QueryParams = queryParams 43 | response, err := sendgrid.API(request) 44 | if err != nil { 45 | log.Println(err) 46 | } else { 47 | fmt.Println(response.StatusCode) 48 | fmt.Println(response.Body) 49 | fmt.Println(response.Headers) 50 | } 51 | } 52 | 53 | // Updateasuppressiongroup : Update a suppression group. 54 | // PATCH /asm/groups/{group_id} 55 | func Updateasuppressiongroup() { 56 | apiKey := os.Getenv("SENDGRID_API_KEY") 57 | host := "https://api.sendgrid.com" 58 | request := sendgrid.GetRequest(apiKey, "/v3/asm/groups/{group_id}", host) 59 | request.Method = "PATCH" 60 | request.Body = []byte(` { 61 | "description": "Suggestions for items our users might like.", 62 | "id": 103, 63 | "name": "Item Suggestions" 64 | }`) 65 | response, err := sendgrid.API(request) 66 | if err != nil { 67 | log.Println(err) 68 | } else { 69 | fmt.Println(response.StatusCode) 70 | fmt.Println(response.Body) 71 | fmt.Println(response.Headers) 72 | } 73 | } 74 | 75 | // Getinformationonasinglesuppressiongroup : Get information on a single suppression group. 76 | // GET /asm/groups/{group_id} 77 | func Getinformationonasinglesuppressiongroup() { 78 | apiKey := os.Getenv("SENDGRID_API_KEY") 79 | host := "https://api.sendgrid.com" 80 | request := sendgrid.GetRequest(apiKey, "/v3/asm/groups/{group_id}", host) 81 | request.Method = "GET" 82 | response, err := sendgrid.API(request) 83 | if err != nil { 84 | log.Println(err) 85 | } else { 86 | fmt.Println(response.StatusCode) 87 | fmt.Println(response.Body) 88 | fmt.Println(response.Headers) 89 | } 90 | } 91 | 92 | // Deleteasuppressiongroup : Delete a suppression group. 93 | // DELETE /asm/groups/{group_id} 94 | func Deleteasuppressiongroup() { 95 | apiKey := os.Getenv("SENDGRID_API_KEY") 96 | host := "https://api.sendgrid.com" 97 | request := sendgrid.GetRequest(apiKey, "/v3/asm/groups/{group_id}", host) 98 | request.Method = "DELETE" 99 | response, err := sendgrid.API(request) 100 | if err != nil { 101 | log.Println(err) 102 | } else { 103 | fmt.Println(response.StatusCode) 104 | fmt.Println(response.Body) 105 | fmt.Println(response.Headers) 106 | } 107 | } 108 | 109 | // Addsuppressionstoasuppressiongroup : Add suppressions to a suppression group 110 | // POST /asm/groups/{group_id}/suppressions 111 | func Addsuppressionstoasuppressiongroup() { 112 | apiKey := os.Getenv("SENDGRID_API_KEY") 113 | host := "https://api.sendgrid.com" 114 | request := sendgrid.GetRequest(apiKey, "/v3/asm/groups/{group_id}/suppressions", host) 115 | request.Method = "POST" 116 | request.Body = []byte(` { 117 | "recipient_emails": [ 118 | "test1@example.com", 119 | "test2@example.com" 120 | ] 121 | }`) 122 | response, err := sendgrid.API(request) 123 | if err != nil { 124 | log.Println(err) 125 | } else { 126 | fmt.Println(response.StatusCode) 127 | fmt.Println(response.Body) 128 | fmt.Println(response.Headers) 129 | } 130 | } 131 | 132 | // Retrieveallsuppressionsforasuppressiongroup : Retrieve all suppressions for a suppression group 133 | // GET /asm/groups/{group_id}/suppressions 134 | func Retrieveallsuppressionsforasuppressiongroup() { 135 | apiKey := os.Getenv("SENDGRID_API_KEY") 136 | host := "https://api.sendgrid.com" 137 | request := sendgrid.GetRequest(apiKey, "/v3/asm/groups/{group_id}/suppressions", host) 138 | request.Method = "GET" 139 | response, err := sendgrid.API(request) 140 | if err != nil { 141 | log.Println(err) 142 | } else { 143 | fmt.Println(response.StatusCode) 144 | fmt.Println(response.Body) 145 | fmt.Println(response.Headers) 146 | } 147 | } 148 | 149 | // Searchforsuppressionswithinagroup : Search for suppressions within a group 150 | // POST /asm/groups/{group_id}/suppressions/search 151 | func Searchforsuppressionswithinagroup() { 152 | apiKey := os.Getenv("SENDGRID_API_KEY") 153 | host := "https://api.sendgrid.com" 154 | request := sendgrid.GetRequest(apiKey, "/v3/asm/groups/{group_id}/suppressions/search", host) 155 | request.Method = "POST" 156 | request.Body = []byte(` { 157 | "recipient_emails": [ 158 | "exists1@example.com", 159 | "exists2@example.com", 160 | "doesnotexists@example.com" 161 | ] 162 | }`) 163 | response, err := sendgrid.API(request) 164 | if err != nil { 165 | log.Println(err) 166 | } else { 167 | fmt.Println(response.StatusCode) 168 | fmt.Println(response.Body) 169 | fmt.Println(response.Headers) 170 | } 171 | } 172 | 173 | // Deleteasuppressionfromasuppressiongroup : Delete a suppression from a suppression group 174 | // DELETE /asm/groups/{group_id}/suppressions/{email} 175 | func Deleteasuppressionfromasuppressiongroup() { 176 | apiKey := os.Getenv("SENDGRID_API_KEY") 177 | host := "https://api.sendgrid.com" 178 | request := sendgrid.GetRequest(apiKey, "/v3/asm/groups/{group_id}/suppressions/{email}", host) 179 | request.Method = "DELETE" 180 | response, err := sendgrid.API(request) 181 | if err != nil { 182 | log.Println(err) 183 | } else { 184 | fmt.Println(response.StatusCode) 185 | fmt.Println(response.Body) 186 | fmt.Println(response.Headers) 187 | } 188 | } 189 | 190 | // Retrieveallsuppressions : Retrieve all suppressions 191 | // GET /asm/suppressions 192 | func Retrieveallsuppressions() { 193 | apiKey := os.Getenv("SENDGRID_API_KEY") 194 | host := "https://api.sendgrid.com" 195 | request := sendgrid.GetRequest(apiKey, "/v3/asm/suppressions", host) 196 | request.Method = "GET" 197 | response, err := sendgrid.API(request) 198 | if err != nil { 199 | log.Println(err) 200 | } else { 201 | fmt.Println(response.StatusCode) 202 | fmt.Println(response.Body) 203 | fmt.Println(response.Headers) 204 | } 205 | } 206 | 207 | // Addrecipientaddressestotheglobalsuppressiongroup : Add recipient addresses to the global suppression group. 208 | // POST /asm/suppressions/global 209 | func Addrecipientaddressestotheglobalsuppressiongroup() { 210 | apiKey := os.Getenv("SENDGRID_API_KEY") 211 | host := "https://api.sendgrid.com" 212 | request := sendgrid.GetRequest(apiKey, "/v3/asm/suppressions/global", host) 213 | request.Method = "POST" 214 | request.Body = []byte(` { 215 | "recipient_emails": [ 216 | "test1@example.com", 217 | "test2@example.com" 218 | ] 219 | }`) 220 | response, err := sendgrid.API(request) 221 | if err != nil { 222 | log.Println(err) 223 | } else { 224 | fmt.Println(response.StatusCode) 225 | fmt.Println(response.Body) 226 | fmt.Println(response.Headers) 227 | } 228 | } 229 | 230 | // RetrieveaGlobalSuppression : Retrieve a Global Suppression 231 | // GET /asm/suppressions/global/{email} 232 | func RetrieveaGlobalSuppression() { 233 | apiKey := os.Getenv("SENDGRID_API_KEY") 234 | host := "https://api.sendgrid.com" 235 | request := sendgrid.GetRequest(apiKey, "/v3/asm/suppressions/global/{email}", host) 236 | request.Method = "GET" 237 | response, err := sendgrid.API(request) 238 | if err != nil { 239 | log.Println(err) 240 | } else { 241 | fmt.Println(response.StatusCode) 242 | fmt.Println(response.Body) 243 | fmt.Println(response.Headers) 244 | } 245 | } 246 | 247 | // DeleteaGlobalSuppression : Delete a Global Suppression 248 | // DELETE /asm/suppressions/global/{email} 249 | func DeleteaGlobalSuppression() { 250 | apiKey := os.Getenv("SENDGRID_API_KEY") 251 | host := "https://api.sendgrid.com" 252 | request := sendgrid.GetRequest(apiKey, "/v3/asm/suppressions/global/{email}", host) 253 | request.Method = "DELETE" 254 | response, err := sendgrid.API(request) 255 | if err != nil { 256 | log.Println(err) 257 | } else { 258 | fmt.Println(response.StatusCode) 259 | fmt.Println(response.Body) 260 | fmt.Println(response.Headers) 261 | } 262 | } 263 | 264 | // Retrieveallsuppressiongroupsforanemailaddress : Retrieve all suppression groups for an email address 265 | // GET /asm/suppressions/{email} 266 | func Retrieveallsuppressiongroupsforanemailaddress() { 267 | apiKey := os.Getenv("SENDGRID_API_KEY") 268 | host := "https://api.sendgrid.com" 269 | request := sendgrid.GetRequest(apiKey, "/v3/asm/suppressions/{email}", host) 270 | request.Method = "GET" 271 | response, err := sendgrid.API(request) 272 | if err != nil { 273 | log.Println(err) 274 | } else { 275 | fmt.Println(response.StatusCode) 276 | fmt.Println(response.Body) 277 | fmt.Println(response.Headers) 278 | } 279 | } 280 | 281 | func main() { 282 | // add your function calls here 283 | } 284 | --------------------------------------------------------------------------------