Ggmail API Golang: Precondition check failed

66 views Asked by At

I am trying to access my gmail api with the scope of:

https://www.googleapis.com/auth/gmail.modify

But I am getting a Precondition check failed error.

The below is the code that I am using to connect to my gmail and use to send a message out:

func ConnectToGmailAPI() *gmail.Service {
    ctx := context.Background()

    err := godotenv.Load()
    if err != nil {
        log.Fatalf("Error loading .env file: %v", err)
    }

    key := os.Getenv("PRIVATE_KEY")

    newkey := strings.Replace(key, "\\n", "\n", -1)

    pKey := []byte(newkey)

    conf := &jwt.Config{
        Email:        os.Getenv("CLIENT_EMAIL"),
        PrivateKeyID: os.Getenv("PRIVATE_KEY_ID"),
        PrivateKey:   pKey,
        Scopes: []string{
            "https://www.googleapis.com/auth/gmail.modify",
        },
        TokenURL: os.Getenv("TOKEN_URL"),
    }

    client := conf.Client(ctx)

    srv, err := gmail.NewService(ctx, option.WithHTTPClient(client))
    if err != nil {
        log.Fatalf("Unable to connect to service %v", err)
    }

    return srv
}

func SendEmail(srv *gmail.Service, subj, msg, to string) (*gmail.Message, error) {
    message, err := gmail.NewUsersMessagesService(srv).Send(
        "me",
        prepMessage(subj, msg, to),
    ).Do()

    if err != nil {
        return &gmail.Message{}, err
    }

    return message, nil

}

func prepMessage(subj, msg, to string) *gmail.Message {
    header := make(map[string]string)
    header["To"] = to
    header["Subject"] = subj
    header["Content-Type"] = "text/plain; charset=utf-8"

    var headers []*gmail.MessagePartHeader
    for k, v := range header {
        headers = append(headers, &gmail.MessagePartHeader{Name: k, Value: v})
    }

    messagePart := &gmail.MessagePart{
        Body: &gmail.MessagePartBody{
            Data: base64.URLEncoding.EncodeToString([]byte(msg)),
        },
        Headers: headers,
    }

    message := gmail.Message{
        Payload: messagePart,
    }

    return &message
}

The below is the actual test I am running:

srv := ConnectToGmailAPI()
    msg, err := SendEmail(srv, "Test", "This is a test sending", "[email protected]")
    if err != nil {
        t.Error(err)
    }

Through research I have found that domain wide delegation is needed which I haved ensured is configured with the same scope I am using as evident of the Domain wide Delegation page screen shot below showing the same scope for the service account that was created:

enter image description here

Furthermore, I know that my ConnectToGmailAPI() function should work because I used the same service account, same environmental variables, and the same config file to set up for a sheets api call which still works. The only thing that I changed between the two implimintations was the scopes in the jwt.Config{} to be gmail.modify. To my understanding the rest of the information should be the same because the service account that I am using is the same.

I would appreciate any insight as to how best I can debug this. The error doesn't really point to a specific problem.

Let me know if you need more information

1

There are 1 answers

2
Linda Lawton - DaImTo On

if you are using a service account then you need to denote the user on your domain that you want it to impersonate this is done by setting Subject

ctx := context.Background()
serviceAccountJSON, err := ioutil.ReadFile(ServiceAccount)
if err != nil {
    log.Fatalf("Warning: Unable to load service account key file %v", err)
}

config, err := google.JWTConfigFromJSON(serviceAccountJSON, SCOPE)
if err != nil {
    log.Fatalf("Warning: Unable to create gmail Client %v", err)
}

config.Subject = "[email protected]"