mail.go raw

   1  package mailinabox
   2  
   3  import (
   4  	"context"
   5  	"errors"
   6  	"fmt"
   7  	"net/http"
   8  	"net/url"
   9  	"strings"
  10  )
  11  
  12  // MailUsers Represents a set of users for a domain.
  13  type MailUsers struct {
  14  	Domain string `json:"domain,omitempty"`
  15  	Users  []User `json:"users,omitempty"`
  16  }
  17  
  18  // User Represents a user.
  19  type User struct {
  20  	Email      string   `json:"email,omitempty"`
  21  	Privileges []string `json:"privileges,omitempty"`
  22  	Status     string   `json:"status,omitempty"`
  23  	Mailbox    string   `json:"mailbox,omitempty"`
  24  }
  25  
  26  // MailAliases Represents a set of aliases for a domain.
  27  type MailAliases struct {
  28  	Domain  string  `json:"domain,omitempty"`
  29  	Aliases []Alias `json:"aliases,omitempty"`
  30  }
  31  
  32  // Alias Represents an alias.
  33  type Alias struct {
  34  	Address          string   `json:"address,omitempty"`
  35  	AddressDisplay   string   `json:"address_display,omitempty"`
  36  	ForwardsTo       []string `json:"forwards_to,omitempty"`
  37  	PermittedSenders []string `json:"permitted_senders,omitempty"`
  38  	Required         bool     `json:"required,omitempty"`
  39  }
  40  
  41  // MailService Mail API.
  42  // https://mailinabox.email/api-docs.html#tag/Mail
  43  type MailService service
  44  
  45  // GetUsers Returns all mail users.
  46  // https://mailinabox.email/api-docs.html#operation/getMailUsers
  47  func (s *MailService) GetUsers(ctx context.Context) ([]MailUsers, error) {
  48  	endpoint := s.client.baseURL.JoinPath("admin", "mail", "users")
  49  
  50  	query := endpoint.Query()
  51  	query.Set("format", "json")
  52  	endpoint.RawQuery = query.Encode()
  53  
  54  	req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), http.NoBody)
  55  	if err != nil {
  56  		return nil, fmt.Errorf("unable to create request: %w", err)
  57  	}
  58  
  59  	var results []MailUsers
  60  
  61  	err = s.client.doJSON(req, &results)
  62  	if err != nil {
  63  		return nil, err
  64  	}
  65  
  66  	return results, nil
  67  }
  68  
  69  // AddUser Adds a new mail user.
  70  // https://mailinabox.email/api-docs.html#operation/addMailUser
  71  func (s *MailService) AddUser(ctx context.Context, email, password, privilege string) (string, error) {
  72  	if email == "" || password == "" || privilege == "" {
  73  		return "", errors.New("email, password, and privilege are required")
  74  	}
  75  
  76  	endpoint := s.client.baseURL.JoinPath("admin", "mail", "users", "add")
  77  
  78  	data := url.Values{}
  79  	data.Set("email", email)
  80  	data.Set("password", password)
  81  	data.Set("privileges", privilege)
  82  
  83  	req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint.String(), strings.NewReader(data.Encode()))
  84  	if err != nil {
  85  		return "", fmt.Errorf("unable to create request: %w", err)
  86  	}
  87  
  88  	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
  89  
  90  	resp, err := s.client.doPlain(req)
  91  	if err != nil {
  92  		return "", err
  93  	}
  94  
  95  	return strings.TrimSpace(string(resp)), nil
  96  }
  97  
  98  // RemoveUser Removes an existing mail user.
  99  // https://mailinabox.email/api-docs.html#operation/removeMailUser
 100  func (s *MailService) RemoveUser(ctx context.Context, email string) (string, error) {
 101  	endpoint := s.client.baseURL.JoinPath("admin", "mail", "users", "remove")
 102  
 103  	data := url.Values{}
 104  	data.Set("email", email)
 105  
 106  	req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint.String(), strings.NewReader(data.Encode()))
 107  	if err != nil {
 108  		return "", fmt.Errorf("unable to create request: %w", err)
 109  	}
 110  
 111  	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 112  
 113  	resp, err := s.client.doPlain(req)
 114  	if err != nil {
 115  		return "", err
 116  	}
 117  
 118  	return strings.TrimSpace(string(resp)), nil
 119  }
 120  
 121  // AddUserPrivilege Adds a privilege to an existing mail user.
 122  // https://mailinabox.email/api-docs.html#operation/addMailUserPrivilege
 123  func (s *MailService) AddUserPrivilege(ctx context.Context, email, privilege string) (string, error) {
 124  	if email == "" || privilege == "" {
 125  		return "", errors.New("email and privilege are required")
 126  	}
 127  
 128  	endpoint := s.client.baseURL.JoinPath("admin", "mail", "users", "privileges", "add")
 129  
 130  	data := url.Values{}
 131  	data.Set("email", email)
 132  	data.Set("privileges", privilege)
 133  
 134  	req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint.String(), strings.NewReader(data.Encode()))
 135  	if err != nil {
 136  		return "", fmt.Errorf("unable to create request: %w", err)
 137  	}
 138  
 139  	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 140  
 141  	resp, err := s.client.doPlain(req)
 142  	if err != nil {
 143  		return "", err
 144  	}
 145  
 146  	return strings.TrimSpace(string(resp)), nil
 147  }
 148  
 149  // RemoveUserPrivilege Adds a privilege to an existing mail user.
 150  // https://mailinabox.email/api-docs.html#operation/removeMailUserPrivilege
 151  func (s *MailService) RemoveUserPrivilege(ctx context.Context, email, privilege string) (string, error) {
 152  	if email == "" {
 153  		return "", errors.New("email is required")
 154  	}
 155  
 156  	endpoint := s.client.baseURL.JoinPath("admin", "mail", "users", "privileges", "remove")
 157  
 158  	data := url.Values{}
 159  	data.Set("email", email)
 160  	data.Set("privileges", privilege)
 161  
 162  	req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint.String(), strings.NewReader(data.Encode()))
 163  	if err != nil {
 164  		return "", fmt.Errorf("unable to create request: %w", err)
 165  	}
 166  
 167  	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 168  
 169  	resp, err := s.client.doPlain(req)
 170  	if err != nil {
 171  		return "", err
 172  	}
 173  
 174  	return strings.TrimSpace(string(resp)), nil
 175  }
 176  
 177  // SetUserPassword Sets a password for an existing mail user.
 178  // https://mailinabox.email/api-docs.html#operation/setMailUserPassword
 179  func (s *MailService) SetUserPassword(ctx context.Context, email, password string) (string, error) {
 180  	if email == "" || password == "" {
 181  		return "", errors.New("email and password are required")
 182  	}
 183  
 184  	endpoint := s.client.baseURL.JoinPath("admin", "mail", "users", "password")
 185  
 186  	data := url.Values{}
 187  	data.Set("email", email)
 188  	data.Set("password", password)
 189  
 190  	req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint.String(), strings.NewReader(data.Encode()))
 191  	if err != nil {
 192  		return "", fmt.Errorf("unable to create request: %w", err)
 193  	}
 194  
 195  	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 196  
 197  	resp, err := s.client.doPlain(req)
 198  	if err != nil {
 199  		return "", err
 200  	}
 201  
 202  	return strings.TrimSpace(string(resp)), nil
 203  }
 204  
 205  // GetUserPrivileges Returns all privileges for an existing mail user.
 206  // https://mailinabox.email/api-docs.html#operation/getMailUserPrivileges
 207  func (s *MailService) GetUserPrivileges(ctx context.Context, email string) (string, error) {
 208  	if email == "" {
 209  		return "", errors.New("email is required")
 210  	}
 211  
 212  	endpoint := s.client.baseURL.JoinPath("admin", "mail", "users", "privileges")
 213  
 214  	query := endpoint.Query()
 215  	query.Set("email", email)
 216  	endpoint.RawQuery = query.Encode()
 217  
 218  	req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), http.NoBody)
 219  	if err != nil {
 220  		return "", fmt.Errorf("unable to create request: %w", err)
 221  	}
 222  
 223  	resp, err := s.client.doPlain(req)
 224  	if err != nil {
 225  		return "", err
 226  	}
 227  
 228  	return strings.TrimSpace(string(resp)), nil
 229  }
 230  
 231  // GetDomains Returns all mail domains.
 232  // https://mailinabox.email/api-docs.html#operation/getMailDomains
 233  func (s *MailService) GetDomains(ctx context.Context) ([]string, error) {
 234  	endpoint := s.client.baseURL.JoinPath("admin", "mail", "domains")
 235  
 236  	req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), http.NoBody)
 237  	if err != nil {
 238  		return nil, fmt.Errorf("unable to create request: %w", err)
 239  	}
 240  
 241  	resp, err := s.client.doPlain(req)
 242  	if err != nil {
 243  		return nil, err
 244  	}
 245  
 246  	domains := strings.Split(strings.TrimSpace(string(resp)), "\n")
 247  
 248  	return domains, nil
 249  }
 250  
 251  // GetAliases Returns all mail aliases.
 252  // https://mailinabox.email/api-docs.html#operation/getMailAliases
 253  func (s *MailService) GetAliases(ctx context.Context) ([]MailAliases, error) {
 254  	endpoint := s.client.baseURL.JoinPath("admin", "mail", "aliases")
 255  
 256  	query := endpoint.Query()
 257  	query.Set("format", "json")
 258  	endpoint.RawQuery = query.Encode()
 259  
 260  	req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), http.NoBody)
 261  	if err != nil {
 262  		return nil, fmt.Errorf("unable to create request: %w", err)
 263  	}
 264  
 265  	var results []MailAliases
 266  
 267  	err = s.client.doJSON(req, &results)
 268  	if err != nil {
 269  		return nil, err
 270  	}
 271  
 272  	return results, nil
 273  }
 274  
 275  // UpsertAlias Adds or updates a mail alias. If updating, you need to set update_if_exists: 1.
 276  // https://mailinabox.email/api-docs.html#operation/upsertMailAlias
 277  func (s *MailService) UpsertAlias(ctx context.Context, updateIfExists bool, address string, forwardsTo, permittedSenders []string) (string, error) {
 278  	if address == "" {
 279  		return "", errors.New("address is required")
 280  	}
 281  
 282  	endpoint := s.client.baseURL.JoinPath("admin", "mail", "aliases", "add")
 283  
 284  	data := url.Values{}
 285  	data.Set("update_if_exists", boolToIntStr(updateIfExists))
 286  	data.Set("address", address)
 287  	data.Set("forwards_to", strings.Join(forwardsTo, ","))
 288  	data.Set("permitted_senders", strings.Join(permittedSenders, ","))
 289  
 290  	req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint.String(), strings.NewReader(data.Encode()))
 291  	if err != nil {
 292  		return "", fmt.Errorf("unable to create request: %w", err)
 293  	}
 294  
 295  	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 296  
 297  	resp, err := s.client.doPlain(req)
 298  	if err != nil {
 299  		return "", err
 300  	}
 301  
 302  	return strings.TrimSpace(string(resp)), nil
 303  }
 304  
 305  // RemoveAliases Removes a mail alias.
 306  // https://mailinabox.email/api-docs.html#operation/removeMailAlias
 307  func (s *MailService) RemoveAliases(ctx context.Context, address string) (string, error) {
 308  	if address == "" {
 309  		return "", errors.New("address is required")
 310  	}
 311  
 312  	endpoint := s.client.baseURL.JoinPath("admin", "mail", "aliases", "remove")
 313  
 314  	data := url.Values{}
 315  	data.Set("address", address)
 316  
 317  	req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint.String(), strings.NewReader(data.Encode()))
 318  	if err != nil {
 319  		return "", fmt.Errorf("unable to create request: %w", err)
 320  	}
 321  
 322  	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 323  
 324  	resp, err := s.client.doPlain(req)
 325  	if err != nil {
 326  		return "", err
 327  	}
 328  
 329  	return strings.TrimSpace(string(resp)), nil
 330  }
 331