-
Notifications
You must be signed in to change notification settings - Fork 3
/
mail.go
142 lines (119 loc) · 3.84 KB
/
mail.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package main
import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"net/http"
"os"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
"google.golang.org/api/gmail/v1"
"google.golang.org/api/option"
)
const (
TOKEN_FILE = "token.json"
CREDENTIALS_FILE = "credentials.json"
)
// Returns the generated client.
func getClient(config *oauth2.Config) (*http.Client, error) {
tok, err := tokenFromFile(TOKEN_FILE)
if err != nil {
return nil, fmt.Errorf("unable to retrieve token from file: %v", err)
}
return config.Client(context.Background(), tok), nil
}
// Request a token from the web, then returns the retrieved token.
func getTokenFromWeb(config *oauth2.Config) (*oauth2.Token, error) {
authURL := config.AuthCodeURL("state-token", oauth2.AccessTypeOffline)
fmt.Printf("Go to the following link in your browser then type the "+
"authorization code: \n%v\n\n", authURL)
fmt.Print("Enter the authorization code: ")
var authCode string
if _, err := fmt.Scan(&authCode); err != nil {
return nil, fmt.Errorf("unable to read authorization code: %v", err)
}
tok, err := config.Exchange(context.TODO(), authCode)
if err != nil {
return nil, fmt.Errorf("unable to retrieve token from web: %v", err)
}
return tok, nil
}
// Retrieves a token from a local file.
func tokenFromFile(file string) (*oauth2.Token, error) {
f, err := os.Open(file)
if err != nil {
return nil, err
}
defer f.Close()
tok := &oauth2.Token{}
err = json.NewDecoder(f).Decode(tok)
return tok, err
}
// Saves a token to a file path.
func saveToken(path string, token *oauth2.Token) error {
fmt.Printf("Saving credential file to: %s\n", path)
f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
return fmt.Errorf("unable to cache oauth token: %v", err)
}
defer f.Close()
json.NewEncoder(f).Encode(token)
return nil
}
// Retrieve a token, saves the token
// The file token.json stores the user's access and refresh tokens
func initMailer() error {
if _, err := os.Stat(TOKEN_FILE); err == nil {
fmt.Println("Token file already exists. Proceeding")
return nil
}
fmt.Println("Token file not found. Generating new token")
b, err := os.ReadFile(CREDENTIALS_FILE)
if err != nil {
return fmt.Errorf("unable to read client secret file: %v", err)
}
// If modifying these scopes, delete your previously saved token.json.
config, err := google.ConfigFromJSON(b, gmail.GmailSendScope)
if err != nil {
return fmt.Errorf("unable to parse client secret file to config: %v", err)
}
token, err := getTokenFromWeb(config)
if err != nil {
return fmt.Errorf("unable to retrieve token from web: %v", err)
}
err = saveToken(TOKEN_FILE, token)
if err != nil {
return fmt.Errorf("unable to save token: %v", err)
}
return nil
}
func sendMail(receiverEmail string, subject string, body string) (bool, error) {
ctx := context.Background()
b, err := os.ReadFile(CREDENTIALS_FILE)
if err != nil {
return false, fmt.Errorf("unable to read client secret file: %v", err)
}
// If modifying these scopes, delete your previously saved token.json.
config, err := google.ConfigFromJSON(b, gmail.GmailSendScope)
if err != nil {
return false, fmt.Errorf("unable to parse client secret file to config: %v", err)
}
client, err := getClient(config)
if err != nil {
return false, fmt.Errorf("unable to get client: %v", err)
}
srv, err := gmail.NewService(ctx, option.WithHTTPClient(client))
if err != nil {
return false, fmt.Errorf("unable to retrieve Gmail client: %v", err)
}
var message gmail.Message
msgStr := fmt.Sprintf("From: 'me'\r\nTo: %s\r\nSubject: %s\r\n\r\n%s", receiverEmail, subject, body)
message.Raw = base64.URLEncoding.EncodeToString([]byte(msgStr))
userID := "me"
_, err = srv.Users.Messages.Send(userID, &message).Do()
if err != nil {
return false, fmt.Errorf("unable to send message: %v", err)
}
return true, nil
}