Send email with attachments in golang
<p>Here is the code:</p>

<pre><code>package main

import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"
    "net/url"
    "os"
    "os/user"
    "path/filepath"

    "golang.org/x/net/context"
    "golang.org/x/oauth2"
    "golang.org/x/oauth2/google"
    "google.golang.org/api/gmail/v1"
    "encoding/base64"
    "io/ioutil"
)

// getClient uses a Context and Config to retrieve a Token
// then generate a Client. It returns the generated Client.
func getClient(ctx context.Context, config *oauth2.Config, configFileName string) *http.Client {
    cacheFile, err := tokenCacheFile(configFileName)
    if err != nil {
        log.Fatalf("Unable to get path to cached credential file. %v", err)
    }
    tok, err := tokenFromFile(cacheFile)
    if err != nil {
        tok = getTokenFromWeb(config)
        saveToken(cacheFile, tok)
    }
    return config.Client(ctx, tok)
}

// getTokenFromWeb uses Config to request a Token.
// It returns the retrieved Token.
func getTokenFromWeb(config *oauth2.Config) *oauth2.Token {
    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", authURL)

    var code string
    if _, err := fmt.Scan(&amp;code); err != nil {
        log.Fatalf("Unable to read authorization code %v", err)
    }

    tok, err := config.Exchange(oauth2.NoContext, code)
    if err != nil {
        log.Fatalf("Unable to retrieve token from web %v", err)
    }
    return tok
}

// tokenCacheFile generates credential file path/filename.
// It returns the generated credential path/filename.
func tokenCacheFile(filename string) (string, error) {
    usr, err := user.Current()
    if err != nil {
        return "", err
    }
    tokenCacheDir := filepath.Join(usr.HomeDir, ".credentials")
    os.MkdirAll(tokenCacheDir, 0700)
    return filepath.Join(tokenCacheDir,
        url.QueryEscape(filename)), err
}

// tokenFromFile retrieves a Token from a given file path.
// It returns the retrieved Token and any read error encountered.
func tokenFromFile(file string) (*oauth2.Token, error) {
    f, err := os.Open(file)
    if err != nil {
        return nil, err
    }
    t := &amp;oauth2.Token{}
    err = json.NewDecoder(f).Decode(t)
    defer f.Close()
    return t, err
}

// saveToken uses a file path to create a file and store the
// token in it.
func saveToken(file string, token *oauth2.Token) {
    fmt.Printf("Saving credential file to: %s\n", file)
    f, err := os.Create(file)
    if err != nil {
        log.Fatalf("Unable to cache oauth token: %v", err)
    }
    defer f.Close()
    json.NewEncoder(f).Encode(token)
}

func main() {
    // Use oauth2.NoContext if there isn't a good context to pass in.
    //ctx := context.TODO()

    ctx := context.Background()

    b, err := ioutil.ReadFile("client_secret.json")
    if err != nil {
        log.Fatalf("Unable to read client secret file: %v", err)
    }

    // If modifying these scopes, delete your previously saved credentials
    // at ~/.credentials/gmail-go-quickstart.json
    sendConfig, err := google.ConfigFromJSON(b, gmail.GmailSendScope)
    if err != nil {
        log.Fatalf("Unable to parse client secret file to config: %v", err)
    }
    sendClient := getClient(ctx, sendConfig, "send.json")

    sendService, err := gmail.New(sendClient)
    if err != nil {
        log.Fatalf("Unable to retrieve gmail Client %v", err)
    }

    if err := SendEmail(ctx, sendService, "jane1988@gmail.com"); err != nil {
        log.Fatalf("failed to send email: %v", err)
    }
}

func SendEmail(ctx context.Context, svc *gmail.Service, email string) error {

    header := make(map[string]string)
    header["To"] = email
    header["Subject"] = "hello there"
    header["MIME-Version"] = "1.0"
    header["Content-Type"] = `text/html; charset="utf-8"`
    header["Content-Transfer-Encoding"] = "base64"

    var msg string
    for k, v := range header {
        msg += fmt.Sprintf("%s: %s\n", k, v)
    }
    msg += "\n" + "Hello, Gmail!"

    gmsg := gmail.Message{
        Raw: encodeWeb64String([]byte(msg)),
    }

    _, err := svc.Users.Messages.Send("me", &amp;gmsg).Do()
    return err
}

func encodeWeb64String(b []byte) string {
    s := base64.URLEncoding.EncodeToString(b)

    var i = len(s) - 1
    for s[i] == '=' {
        i--
    }

    return s[0 : i + 1]
}
</code></pre>

<p>This works perfectly, but without attachments. How can I attach files to the mail?</p>