├── .gitignore ├── LICENSE ├── Readme.md ├── sms.go ├── sms_example_test.go └── sms_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | .envrc 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2016 TJ Holowaychuk tj@tjholowaychuk.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | 'Software'), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # go-sms 2 | 3 | Package sms provides a small wrapper around AWS SNS to make SMS usage less obscure, 4 | conflating APIs FTW. 5 | 6 | ## Example 7 | 8 | ```` go 9 | sms.Send("Hello World", "+19999999999") 10 | ```` 11 | 12 | ## Running Tests 13 | 14 | First export the `PHONE` environment variable to test against your number, and set your AWS credentials via the `AWS_*` environment variables. 15 | 16 | ## Badges 17 | 18 | [![GoDoc](https://godoc.org/github.com/tj/go-sms?status.svg)](https://godoc.org/github.com/tj/go-sms) 19 | ![](https://img.shields.io/badge/license-MIT-blue.svg) 20 | ![](https://img.shields.io/badge/status-stable-green.svg) 21 | [![](http://apex.sh/images/badge.svg)](https://apex.sh/ping/) 22 | 23 | --- 24 | 25 | > [tjholowaychuk.com](http://tjholowaychuk.com)  ·  26 | > GitHub [@tj](https://github.com/tj)  ·  27 | > Twitter [@tjholowaychuk](https://twitter.com/tjholowaychuk) 28 | -------------------------------------------------------------------------------- /sms.go: -------------------------------------------------------------------------------- 1 | // Package sms provides a small wrapper around AWS SNS SMS support. 2 | package sms 3 | 4 | import ( 5 | "fmt" 6 | 7 | "github.com/aws/aws-sdk-go/aws" 8 | "github.com/aws/aws-sdk-go/aws/session" 9 | "github.com/aws/aws-sdk-go/service/sns" 10 | "github.com/aws/aws-sdk-go/service/sns/snsiface" 11 | ) 12 | 13 | // Type of SMS delivery mode. 14 | type Type string 15 | 16 | const ( 17 | // Promotional are non-critical messages, such as marketing messages. 18 | // Amazon SNS optimizes the message delivery to incur the lowest cost. 19 | Promotional Type = "Promotional" 20 | 21 | // Transactional messages are critical messages that support 22 | // customer transactions, such as one-time passcodes for multi-factor authentication. 23 | // Amazon SNS optimizes the message delivery to achieve the highest reliability. 24 | Transactional = "Transactional" 25 | ) 26 | 27 | // Defaults. 28 | var ( 29 | DefaultMaxPrice = 0.01 30 | DefaultType = Promotional 31 | ) 32 | 33 | // SMS configures an SNS SMS client. 34 | type SMS struct { 35 | Service snsiface.SNSAPI // Service implementation 36 | SenderID string // SenderID (optional) 37 | Type Type // Type of SMS delivery mode 38 | MaxPrice float64 // MaxPrice (defaults to $0.01) 39 | } 40 | 41 | // Send `message` to `number`. 42 | func (s *SMS) Send(message, number string) error { 43 | attrs := map[string]*sns.MessageAttributeValue{} 44 | 45 | if s.SenderID != "" { 46 | attrs["AWS.SNS.SMS.SenderID"] = &sns.MessageAttributeValue{ 47 | DataType: aws.String("String"), 48 | StringValue: &s.SenderID, 49 | } 50 | } 51 | 52 | maxPrice := s.MaxPrice 53 | if maxPrice == 0 { 54 | maxPrice = DefaultMaxPrice 55 | } 56 | 57 | attrs["AWS.SNS.SMS.MaxPrice"] = &sns.MessageAttributeValue{ 58 | DataType: aws.String("String"), 59 | StringValue: aws.String(fmt.Sprintf("%0.5f", maxPrice)), 60 | } 61 | 62 | kind := s.Type 63 | if kind == "" { 64 | kind = DefaultType 65 | } 66 | 67 | attrs["AWS.SNS.SMS.SMSType"] = &sns.MessageAttributeValue{ 68 | DataType: aws.String("String"), 69 | StringValue: aws.String(string(kind)), 70 | } 71 | 72 | params := &sns.PublishInput{ 73 | Message: &message, 74 | PhoneNumber: &number, 75 | MessageAttributes: attrs, 76 | } 77 | 78 | _, err := s.Service.Publish(params) 79 | return err 80 | } 81 | 82 | // Send `message` to `number` using defaults. 83 | func Send(message, number string) error { 84 | service := sns.New(session.New(aws.NewConfig())) 85 | sms := SMS{Service: service} 86 | return sms.Send(message, number) 87 | } 88 | -------------------------------------------------------------------------------- /sms_example_test.go: -------------------------------------------------------------------------------- 1 | package sms_test 2 | 3 | import ( 4 | env "github.com/segmentio/go-env" 5 | 6 | "github.com/tj/go-sms" 7 | ) 8 | 9 | // Example showing the most basic usage and defaults. 10 | func Example() { 11 | sms.Send("Hello World", env.MustGet("PHONE")) 12 | } 13 | 14 | // Example showing how to override the defaults unless you want to 15 | // go all-out and use the SMS struct directly. 16 | func Example_overrides() { 17 | sms.DefaultMaxPrice = 0.5 18 | sms.DefaultType = sms.Transactional 19 | sms.Send("Hello World", env.MustGet("PHONE")) 20 | } 21 | -------------------------------------------------------------------------------- /sms_test.go: -------------------------------------------------------------------------------- 1 | package sms_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/aws/session" 8 | "github.com/aws/aws-sdk-go/service/sns" 9 | env "github.com/segmentio/go-env" 10 | "github.com/stretchr/testify/assert" 11 | 12 | "github.com/tj/go-sms" 13 | ) 14 | 15 | var number = env.MustGet("PHONE") 16 | 17 | func TestSMS_Send(t *testing.T) { 18 | service := sns.New(session.New(aws.NewConfig())) 19 | 20 | sms := &sms.SMS{ 21 | Service: service, 22 | Type: sms.Transactional, 23 | MaxPrice: 0.50, 24 | } 25 | 26 | err := sms.Send("Hello from SMS.Send()", number) 27 | assert.NoError(t, err, "error sending") 28 | } 29 | 30 | func TestSend(t *testing.T) { 31 | err := sms.Send("Hello from Send()", number) 32 | assert.NoError(t, err, "error sending") 33 | } 34 | --------------------------------------------------------------------------------