6 "github.com/hashicorp/terraform/helper/schema"
7 "github.com/hashicorp/terraform/helper/resource"
8 "github.com/mailgun/mailgun-go/v3"
13 func resourceMailgunDomain() *schema.Resource {
14 return &schema.Resource{
19 Importer: &schema.ResourceImporter{
20 State: ImportStatePassthroughDomain,
23 Schema: map[string]*schema.Schema{
24 "name": &schema.Schema{
25 Type: schema.TypeString,
30 "spam_action": &schema.Schema{
31 Type: schema.TypeString,
37 "smtp_password": &schema.Schema{
38 Type: schema.TypeString,
43 "smtp_login": &schema.Schema{
44 Type: schema.TypeString,
48 "wildcard": &schema.Schema{
49 Type: schema.TypeBool,
55 "created_at": &schema.Schema{
56 Type: schema.TypeString,
61 "state": &schema.Schema{
62 Type: schema.TypeString,
66 "force_dkim_authority": &schema.Schema{
67 Type: schema.TypeBool,
72 "dkim_key_size": &schema.Schema{
79 "ips": &schema.Schema{
80 Type: schema.TypeList,
84 Elem: &schema.Schema{Type: schema.TypeString},
87 "credentials": &schema.Schema{
88 Type: schema.TypeList,
90 Elem: &schema.Resource{
91 Schema: map[string]*schema.Schema{
92 "created_at": &schema.Schema{
93 Type: schema.TypeString,
96 "login": &schema.Schema{
97 Type: schema.TypeString,
100 "password": &schema.Schema{
101 Type: schema.TypeString,
108 "open_tracking_settings_active": &schema.Schema{
109 Type: schema.TypeBool,
114 "click_tracking_settings_active": &schema.Schema{
115 Type: schema.TypeBool,
120 "unsubscribe_tracking_settings_active": &schema.Schema{
121 Type: schema.TypeBool,
125 "unsubscribe_tracking_settings_html_footer": &schema.Schema{
126 Type: schema.TypeString,
128 Default: "\n<br>\n<p><a href=\"%unsubscribe_url%\">unsubscribe</a></p>\n",
130 "unsubscribe_tracking_settings_text_footer": &schema.Schema{
131 Type: schema.TypeString,
133 Default: "\n\nTo unsubscribe click: <%unsubscribe_url%>\n\n",
136 "require_tls": &schema.Schema{
137 Type: schema.TypeBool,
142 "skip_verification": &schema.Schema{
143 Type: schema.TypeBool,
148 "receiving_records": &schema.Schema{
149 Type: schema.TypeList,
151 Elem: &schema.Resource{
152 Schema: map[string]*schema.Schema{
153 "name": &schema.Schema{
154 Type: schema.TypeString,
157 "priority": &schema.Schema{
158 Type: schema.TypeString,
161 "record_type": &schema.Schema{
162 Type: schema.TypeString,
165 "valid": &schema.Schema{
166 Type: schema.TypeString,
169 "value": &schema.Schema{
170 Type: schema.TypeString,
177 "sending_records": &schema.Schema{
178 Type: schema.TypeList,
180 Elem: &schema.Resource{
181 Schema: map[string]*schema.Schema{
182 "name": &schema.Schema{
183 Type: schema.TypeString,
186 "priority": &schema.Schema{
187 Type: schema.TypeString,
190 "record_type": &schema.Schema{
191 Type: schema.TypeString,
194 "valid": &schema.Schema{
195 Type: schema.TypeString,
198 "value": &schema.Schema{
199 Type: schema.TypeString,
209 func interfaceToStringTab(i interface{}) []string {
210 aInterface := i.([]interface{})
211 aString := make([]string, len(aInterface))
212 for i, v := range aInterface {
213 aString[i] = v.(string)
217 func CreateDomain(d *schema.ResourceData, meta interface{}) error {
218 mg := meta.(*mailgun.MailgunImpl)
219 ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
222 log.Printf("[DEBUG] creating mailgun domain: %s", d.Id())
224 creationResponse, err := mg.CreateDomain(ctx, d.Get("name").(string), &mailgun.CreateDomainOptions{
225 Password: d.Get("smtp_password").(string),
226 SpamAction: mailgun.SpamAction(d.Get("spam_action").(string)),
227 Wildcard: d.Get("wildcard").(bool),
228 ForceDKIMAuthority: d.Get("force_dkim_authority").(bool),
229 DKIMKeySize: d.Get("dkim_key_size").(int),
230 IPS: interfaceToStringTab(d.Get("ips")),
234 return fmt.Errorf("Error creating mailgun domain: %s", err.Error())
237 mg = mailgun.NewMailgun(creationResponse.Domain.Name, mg.APIKey())
239 for _, i := range d.Get("credentials").([]interface{}) {
240 credential := i.(map[string]interface{})
241 err = mg.CreateCredential(ctx, credential["login"].(string), credential["password"].(string))
243 return fmt.Errorf("Error creating mailgun credential: %s", err.Error())
247 err = mg.UpdateUnsubscribeTracking(ctx, creationResponse.Domain.Name, boolToString(d.Get("unsubscribe_tracking_settings_active").(bool)), d.Get("unsubscribe_tracking_settings_html_footer").(string), d.Get("unsubscribe_tracking_settings_text_footer").(string))
249 return fmt.Errorf("Error updating mailgun unsubscribe tracking settings: %s", err.Error())
252 err = mg.UpdateOpenTracking(ctx, creationResponse.Domain.Name, boolToString(d.Get("open_tracking_settings_active").(bool)))
254 return fmt.Errorf("Error updating mailgun open tracking settings: %s", err.Error())
257 err = mg.UpdateClickTracking(ctx, creationResponse.Domain.Name, boolToString(d.Get("click_tracking_settings_active").(bool)))
259 return fmt.Errorf("Error updating mailgun click tracking settings: %s", err.Error())
262 err = mg.UpdateDomainConnection(ctx, creationResponse.Domain.Name, mailgun.DomainConnection{RequireTLS: d.Get("require_tls").(bool), SkipVerification: d.Get("skip_verification").(bool)})
264 return fmt.Errorf("Error updating mailgun connexion settings: %s", err.Error())
267 d.SetId(creationResponse.Domain.Name)
269 return ReadDomain(d, meta)
272 func UpdateDomain(d *schema.ResourceData, meta interface{}) error {
273 mg := meta.(*mailgun.MailgunImpl)
274 ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
276 domainName := d.Get("name").(string)
277 mg = mailgun.NewMailgun(domainName, mg.APIKey())
279 log.Printf("[DEBUG] updating mailgun domain: %s", d.Id())
281 if d.HasChange("unsubscribe_tracking_settings_active") || d.HasChange("unsubscribe_tracking_settings_html_footer") || d.HasChange("unsubscribe_tracking_settings_text_footer") {
282 err := mg.UpdateUnsubscribeTracking(ctx, domainName, boolToString(d.Get("unsubscribe_tracking_settings_active").(bool)), d.Get("unsubscribe_tracking_settings_html_footer").(string), d.Get("unsubscribe_tracking_settings_text_footer").(string))
284 return fmt.Errorf("Error updating mailgun unsubscribe tracking settings: %s", err.Error())
287 if d.HasChange("open_tracking_settings_active") {
288 err := mg.UpdateOpenTracking(ctx, domainName, boolToString(d.Get("open_tracking_settings_active").(bool)))
290 return fmt.Errorf("Error updating mailgun open tracking settings: %s", err.Error())
294 if d.HasChange("click_tracking_settings_active") {
295 err := mg.UpdateClickTracking(ctx, domainName, boolToString(d.Get("click_tracking_settings_active").(bool)))
297 return fmt.Errorf("Error updating mailgun click tracking settings: %s", err.Error())
301 if d.HasChange("require_tls") || d.HasChange("skip_verification") {
302 err := mg.UpdateDomainConnection(ctx, domainName, mailgun.DomainConnection{RequireTLS: d.Get("require_tls").(bool), SkipVerification: d.Get("skip_verification").(bool)})
304 return fmt.Errorf("Error updating mailgun connexion settings: %s", err.Error())
308 if d.HasChange("credentials") {
309 old, new := d.GetChange("credentials")
310 for _, i := range old.([]interface{}) {
311 oldCredential := i.(map[string]interface{})
313 for _, j := range new.([]interface{}) {
314 newCredential := j.(map[string]interface{})
315 if oldCredential["login"] == newCredential["login"] {
317 if oldCredential["password"] != newCredential["password"] && newCredential["password"] != "" {
318 err := mg.ChangeCredentialPassword(ctx, oldCredential["login"].(string), newCredential["password"].(string))
320 return fmt.Errorf("Error updating mailgun credential password: %s", err.Error())
327 err := mg.DeleteCredential(ctx, oldCredential["login"].(string))
329 return fmt.Errorf("Error deleting mailgun credential : %s", err.Error())
334 for _, i := range new.([]interface{}) {
335 newCredential := i.(map[string]interface{})
337 for _, j := range old.([]interface{}) {
338 oldCredential := j.(map[string]interface{})
339 if oldCredential["login"] == newCredential["login"] {
345 err := mg.CreateCredential(ctx, newCredential["login"].(string), newCredential["password"].(string))
347 return fmt.Errorf("Error creating mailgun credential : %s", err.Error())
353 return ReadDomain(d, meta)
356 func DeleteDomain(d *schema.ResourceData, meta interface{}) error {
357 mg := meta.(*mailgun.MailgunImpl)
358 ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
361 log.Printf("[DEBUG] Deleting mailgun domain: %s", d.Id())
363 err := mg.DeleteDomain(ctx, d.Get("name").(string))
368 func ReadDomain(d *schema.ResourceData, meta interface{}) error {
369 mg := meta.(*mailgun.MailgunImpl)
370 ctx, cancel := context.WithTimeout(context.Background(), time.Second*120)
373 mg = mailgun.NewMailgun(domainName, mg.APIKey())
375 domainResponse, err := mg.GetDomain(ctx, domainName)
377 return fmt.Errorf("Error Getting mailgun domain Details for %s: Error: %s", d.Id(), err)
380 d.Set("created_at", domainResponse.Domain.CreatedAt.String())
381 d.Set("smtd_login", domainResponse.Domain.SMTPLogin)
382 d.Set("name", domainResponse.Domain.Name)
383 d.Set("smtd_password", domainResponse.Domain.SMTPPassword)
384 d.Set("wildcard", domainResponse.Domain.Wildcard)
385 d.Set("spam_action", domainResponse.Domain.SpamAction)
386 d.Set("state", domainResponse.Domain.State)
388 simpleReceivingRecords := make([]map[string]interface{}, len(domainResponse.ReceivingDNSRecords))
389 for i, r := range domainResponse.ReceivingDNSRecords {
390 simpleReceivingRecords[i] = make(map[string]interface{})
391 simpleReceivingRecords[i]["priority"] = r.Priority
392 simpleReceivingRecords[i]["name"] = r.Name
393 simpleReceivingRecords[i]["valid"] = r.Valid
394 simpleReceivingRecords[i]["value"] = r.Value
395 simpleReceivingRecords[i]["record_type"] = r.RecordType
397 d.Set("receiving_records", simpleReceivingRecords)
399 simpleSendingRecords := make([]map[string]interface{}, len(domainResponse.SendingDNSRecords))
400 for i, r := range domainResponse.SendingDNSRecords {
401 simpleSendingRecords[i] = make(map[string]interface{})
402 simpleSendingRecords[i]["name"] = r.Name
403 simpleSendingRecords[i]["priority"] = r.Priority
404 simpleSendingRecords[i]["valid"] = r.Valid
405 simpleSendingRecords[i]["value"] = r.Value
406 simpleSendingRecords[i]["record_type"] = r.RecordType
408 d.Set("sending_records", simpleSendingRecords)
410 domainConnection, err := mg.GetDomainConnection(ctx, domainName)
412 return fmt.Errorf("Error Getting mailgun domain connection Details for %s: Error: %s", d.Id(), err)
414 d.Set("require_tls", domainConnection.RequireTLS)
415 d.Set("skip_verification", domainConnection.SkipVerification)
417 domainTracking, err := mg.GetDomainTracking(ctx, domainName)
419 return fmt.Errorf("Error Getting mailgun domain tracking Details for %s: Error: %s", d.Id(), err)
422 d.Set("open_tracking_settings_active", domainTracking.Open.Active)
424 d.Set("click_tracking_settings_active", domainTracking.Click.Active)
425 d.Set("unsubscribe_tracking_settings_active", domainTracking.Unsubscribe.Active)
426 d.Set("unsubscribe_tracking_settings_html_footer", domainTracking.Unsubscribe.HTMLFooter)
427 d.Set("unsubscribe_tracking_settings_text_footer", domainTracking.Unsubscribe.TextFooter)
429 ipAddress, err := getIps(ctx, mg)
432 return fmt.Errorf("Error Getting mailgun domain ips1 for %s: Error: %s", d.Id(), err)
434 ips := make([]string, len(ipAddress))
435 for i, r := range ipAddress {
441 credentialsResponse, err := ListCredentials(domainName, mg.APIKey())
443 return fmt.Errorf("Error Getting mailgun credentials for %s: Error: %s", d.Id(), err)
446 credentials := make([]map[string]interface{}, len(credentialsResponse))
447 credentialsConf := d.Get("credentials").([]interface{})
448 for i, r := range credentialsResponse {
449 credentials[i] = make(map[string]interface{})
450 credentials[i]["created_at"] = r.CreatedAt.String()
451 credentials[i]["login"] = r.Login
452 for _, c:= range credentialsConf {
453 conf:=c.(map[string]interface{})
454 if conf["login"] == credentials[i]["login"] {
455 credentials[i]["password"] = conf["password"]
460 d.Set("credentials", credentials)
467 func boolToString(b bool) string {
474 func ListCredentials(domain, apiKey string) ([]mailgun.Credential, error) {
475 mg := mailgun.NewMailgun(domain, apiKey)
476 it := mg.ListCredentials(nil)
478 ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
481 var page, result []mailgun.Credential
482 for it.Next(ctx, &page) {
483 result = append(result, page...)
492 func ImportStatePassthroughDomain(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
493 if _, ok := d.GetOk("dkim_key_size"); !ok {
494 d.Set("dkim_key_size", 1024)
497 if _, ok := d.GetOk("force_dkim_authority"); !ok {
498 d.Set("force_dkim_authority", false)
500 return []*schema.ResourceData{d}, nil
503 func getIps(ctx context.Context,mg *mailgun.MailgunImpl) ([]mailgun.IPAddress, error){
504 var ipAddress []mailgun.IPAddress
505 log.Printf("[DEBUG] begin to fetch ips for %s",mg.Domain())
506 err := resource.Retry(2*time.Minute, func() *resource.RetryError {
508 ipAddress, err = mg.ListDomainIPS(ctx)
510 log.Printf("[DEBUG] failed to fetch ips for %s",mg.Domain())
511 return resource.RetryableError(err)
513 log.Printf("[DEBUG] managed to fetch ips for %s",mg.Domain())
517 return ipAddress, err