1package mailgun 2 3import ( 4 "encoding/json" 5 "fmt" 6 "strconv" 7) 8 9// A mailing list may have one of three membership modes. 10// ReadOnly specifies that nobody, including Members, 11// may send messages to the mailing list. 12// Messages distributed on such lists come from list administrator accounts only. 13// Members specifies that only those who subscribe to the mailing list may send messages. 14// Everyone specifies that anyone and everyone may both read and submit messages 15// to the mailing list, including non-subscribers. 16const ( 17 ReadOnly = "readonly" 18 Members = "members" 19 Everyone = "everyone" 20) 21 22// Mailing list members have an attribute that determines if they've subscribed to the mailing list or not. 23// This attribute may be used to filter the results returned by GetSubscribers(). 24// All, Subscribed, and Unsubscribed provides a convenient and readable syntax for specifying the scope of the search. 25var ( 26 All *bool = nil 27 Subscribed *bool = &yes 28 Unsubscribed *bool = &no 29) 30 31// yes and no are variables which provide us the ability to take their addresses. 32// Subscribed and Unsubscribed are pointers to these booleans. 33// 34// We use a pointer to boolean as a kind of trinary data type: 35// if nil, the relevant data type remains unspecified. 36// Otherwise, its value is either true or false. 37var ( 38 yes bool = true 39 no bool = false 40) 41 42// A List structure provides information for a mailing list. 43// 44// AccessLevel may be one of ReadOnly, Members, or Everyone. 45type List struct { 46 Address string `json:"address",omitempty"` 47 Name string `json:"name",omitempty"` 48 Description string `json:"description",omitempty"` 49 AccessLevel string `json:"access_level",omitempty"` 50 CreatedAt string `json:"created_at",omitempty"` 51 MembersCount int `json:"members_count",omitempty"` 52} 53 54// A Member structure represents a member of the mailing list. 55// The Vars field can represent any JSON-encodable data. 56type Member struct { 57 Address string `json:"address,omitempty"` 58 Name string `json:"name,omitempty"` 59 Subscribed *bool `json:"subscribed,omitempty"` 60 Vars map[string]interface{} `json:"vars,omitempty"` 61} 62 63// GetLists returns the specified set of mailing lists administered by your account. 64func (mg *MailgunImpl) GetLists(limit, skip int, filter string) (int, []List, error) { 65 r := newHTTPRequest(generatePublicApiUrl(mg, listsEndpoint)) 66 r.setClient(mg.Client()) 67 r.setBasicAuth(basicAuthUser, mg.ApiKey()) 68 p := newUrlEncodedPayload() 69 if limit != DefaultLimit { 70 p.addValue("limit", strconv.Itoa(limit)) 71 } 72 if skip != DefaultSkip { 73 p.addValue("skip", strconv.Itoa(skip)) 74 } 75 if filter != "" { 76 p.addValue("address", filter) 77 } 78 var envelope struct { 79 Items []List `json:"items"` 80 TotalCount int `json:"total_count"` 81 } 82 response, err := makeRequest(r, "GET", p) 83 if err != nil { 84 return -1, nil, err 85 } 86 err = response.parseFromJSON(&envelope) 87 return envelope.TotalCount, envelope.Items, err 88} 89 90// CreateList creates a new mailing list under your Mailgun account. 91// You need specify only the Address and Name members of the prototype; 92// Description, and AccessLevel are optional. 93// If unspecified, Description remains blank, 94// while AccessLevel defaults to Everyone. 95func (mg *MailgunImpl) CreateList(prototype List) (List, error) { 96 r := newHTTPRequest(generatePublicApiUrl(mg, listsEndpoint)) 97 r.setClient(mg.Client()) 98 r.setBasicAuth(basicAuthUser, mg.ApiKey()) 99 p := newUrlEncodedPayload() 100 if prototype.Address != "" { 101 p.addValue("address", prototype.Address) 102 } 103 if prototype.Name != "" { 104 p.addValue("name", prototype.Name) 105 } 106 if prototype.Description != "" { 107 p.addValue("description", prototype.Description) 108 } 109 if prototype.AccessLevel != "" { 110 p.addValue("access_level", prototype.AccessLevel) 111 } 112 response, err := makePostRequest(r, p) 113 if err != nil { 114 return List{}, err 115 } 116 var l List 117 err = response.parseFromJSON(&l) 118 return l, err 119} 120 121// DeleteList removes all current members of the list, then removes the list itself. 122// Attempts to send e-mail to the list will fail subsequent to this call. 123func (mg *MailgunImpl) DeleteList(addr string) error { 124 r := newHTTPRequest(generatePublicApiUrl(mg, listsEndpoint) + "/" + addr) 125 r.setClient(mg.Client()) 126 r.setBasicAuth(basicAuthUser, mg.ApiKey()) 127 _, err := makeDeleteRequest(r) 128 return err 129} 130 131// GetListByAddress allows your application to recover the complete List structure 132// representing a mailing list, so long as you have its e-mail address. 133func (mg *MailgunImpl) GetListByAddress(addr string) (List, error) { 134 r := newHTTPRequest(generatePublicApiUrl(mg, listsEndpoint) + "/" + addr) 135 r.setClient(mg.Client()) 136 r.setBasicAuth(basicAuthUser, mg.ApiKey()) 137 response, err := makeGetRequest(r) 138 if err != nil { 139 return List{}, err 140 } 141 142 var envelope struct { 143 List `json:"list"` 144 } 145 err = response.parseFromJSON(&envelope) 146 return envelope.List, err 147} 148 149// UpdateList allows you to change various attributes of a list. 150// Address, Name, Description, and AccessLevel are all optional; 151// only those fields which are set in the prototype will change. 152// 153// Be careful! If changing the address of a mailing list, 154// e-mail sent to the old address will not succeed. 155// Make sure you account for the change accordingly. 156func (mg *MailgunImpl) UpdateList(addr string, prototype List) (List, error) { 157 r := newHTTPRequest(generatePublicApiUrl(mg, listsEndpoint) + "/" + addr) 158 r.setClient(mg.Client()) 159 r.setBasicAuth(basicAuthUser, mg.ApiKey()) 160 p := newUrlEncodedPayload() 161 if prototype.Address != "" { 162 p.addValue("address", prototype.Address) 163 } 164 if prototype.Name != "" { 165 p.addValue("name", prototype.Name) 166 } 167 if prototype.Description != "" { 168 p.addValue("description", prototype.Description) 169 } 170 if prototype.AccessLevel != "" { 171 p.addValue("access_level", prototype.AccessLevel) 172 } 173 var l List 174 response, err := makePutRequest(r, p) 175 if err != nil { 176 return l, err 177 } 178 err = response.parseFromJSON(&l) 179 return l, err 180} 181 182// GetMembers returns the list of members belonging to the indicated mailing list. 183// The s parameter can be set to one of three settings to help narrow the returned data set: 184// All indicates that you want both Members and unsubscribed members alike, while 185// Subscribed and Unsubscribed indicate you want only those eponymous subsets. 186func (mg *MailgunImpl) GetMembers(limit, skip int, s *bool, addr string) (int, []Member, error) { 187 r := newHTTPRequest(generateMemberApiUrl(mg, listsEndpoint, addr)) 188 r.setClient(mg.Client()) 189 r.setBasicAuth(basicAuthUser, mg.ApiKey()) 190 p := newUrlEncodedPayload() 191 if limit != DefaultLimit { 192 p.addValue("limit", strconv.Itoa(limit)) 193 } 194 if skip != DefaultSkip { 195 p.addValue("skip", strconv.Itoa(skip)) 196 } 197 if s != nil { 198 p.addValue("subscribed", yesNo(*s)) 199 } 200 var envelope struct { 201 TotalCount int `json:"total_count"` 202 Items []Member `json:"items"` 203 } 204 response, err := makeRequest(r, "GET", p) 205 if err != nil { 206 return -1, nil, err 207 } 208 err = response.parseFromJSON(&envelope) 209 return envelope.TotalCount, envelope.Items, err 210} 211 212// GetMemberByAddress returns a complete Member structure for a member of a mailing list, 213// given only their subscription e-mail address. 214func (mg *MailgunImpl) GetMemberByAddress(s, l string) (Member, error) { 215 r := newHTTPRequest(generateMemberApiUrl(mg, listsEndpoint, l) + "/" + s) 216 r.setClient(mg.Client()) 217 r.setBasicAuth(basicAuthUser, mg.ApiKey()) 218 response, err := makeGetRequest(r) 219 if err != nil { 220 return Member{}, err 221 } 222 var envelope struct { 223 Member Member `json:"member"` 224 } 225 err = response.parseFromJSON(&envelope) 226 return envelope.Member, err 227} 228 229// CreateMember registers a new member of the indicated mailing list. 230// If merge is set to true, then the registration may update an existing Member's settings. 231// Otherwise, an error will occur if you attempt to add a member with a duplicate e-mail address. 232func (mg *MailgunImpl) CreateMember(merge bool, addr string, prototype Member) error { 233 vs, err := json.Marshal(prototype.Vars) 234 if err != nil { 235 return err 236 } 237 238 r := newHTTPRequest(generateMemberApiUrl(mg, listsEndpoint, addr)) 239 r.setClient(mg.Client()) 240 r.setBasicAuth(basicAuthUser, mg.ApiKey()) 241 p := newFormDataPayload() 242 p.addValue("upsert", yesNo(merge)) 243 p.addValue("address", prototype.Address) 244 p.addValue("name", prototype.Name) 245 p.addValue("vars", string(vs)) 246 if prototype.Subscribed != nil { 247 p.addValue("subscribed", yesNo(*prototype.Subscribed)) 248 } 249 _, err = makePostRequest(r, p) 250 return err 251} 252 253// UpdateMember lets you change certain details about the indicated mailing list member. 254// Address, Name, Vars, and Subscribed fields may be changed. 255func (mg *MailgunImpl) UpdateMember(s, l string, prototype Member) (Member, error) { 256 r := newHTTPRequest(generateMemberApiUrl(mg, listsEndpoint, l) + "/" + s) 257 r.setClient(mg.Client()) 258 r.setBasicAuth(basicAuthUser, mg.ApiKey()) 259 p := newFormDataPayload() 260 if prototype.Address != "" { 261 p.addValue("address", prototype.Address) 262 } 263 if prototype.Name != "" { 264 p.addValue("name", prototype.Name) 265 } 266 if prototype.Vars != nil { 267 vs, err := json.Marshal(prototype.Vars) 268 if err != nil { 269 return Member{}, err 270 } 271 p.addValue("vars", string(vs)) 272 } 273 if prototype.Subscribed != nil { 274 p.addValue("subscribed", yesNo(*prototype.Subscribed)) 275 } 276 response, err := makePutRequest(r, p) 277 if err != nil { 278 return Member{}, err 279 } 280 var envelope struct { 281 Member Member `json:"member"` 282 } 283 err = response.parseFromJSON(&envelope) 284 return envelope.Member, err 285} 286 287// DeleteMember removes the member from the list. 288func (mg *MailgunImpl) DeleteMember(member, addr string) error { 289 r := newHTTPRequest(generateMemberApiUrl(mg, listsEndpoint, addr) + "/" + member) 290 r.setClient(mg.Client()) 291 r.setBasicAuth(basicAuthUser, mg.ApiKey()) 292 _, err := makeDeleteRequest(r) 293 return err 294} 295 296// CreateMemberList registers multiple Members and non-Member members to a single mailing list 297// in a single round-trip. 298// u indicates if the existing members should be updated or duplicates should be updated. 299// Use All to elect not to provide a default. 300// The newMembers list can take one of two JSON-encodable forms: an slice of strings, or 301// a slice of Member structures. 302// If a simple slice of strings is passed, each string refers to the member's e-mail address. 303// Otherwise, each Member needs to have at least the Address field filled out. 304// Other fields are optional, but may be set according to your needs. 305func (mg *MailgunImpl) CreateMemberList(u *bool, addr string, newMembers []interface{}) error { 306 r := newHTTPRequest(generateMemberApiUrl(mg, listsEndpoint, addr) + ".json") 307 r.setClient(mg.Client()) 308 r.setBasicAuth(basicAuthUser, mg.ApiKey()) 309 p := newFormDataPayload() 310 if u != nil { 311 p.addValue("upsert", yesNo(*u)) 312 } 313 bs, err := json.Marshal(newMembers) 314 if err != nil { 315 return err 316 } 317 fmt.Println(string(bs)) 318 p.addValue("members", string(bs)) 319 _, err = makePostRequest(r, p) 320 return err 321} 322