Search code examples
c#google-api-dotnet-clientservice-accountsgoogle-workspace

Batch Request - SendAs Emails


Is there a way to do a batch request to get SendAs emails from multiple or all users?

Currently we are using a service account with user impersonation to go through each user and get the SendAs email list - lot of requests.

  1. GmailService as service - this is impersonated as the user.
  2. service.Users.Settings.SendAs.List("me").Execute();

P.S. I posted this in google group, but just read a post that said the forum is now read-only! It's weird that it allowed me to make a new post (and obviously i was thinking that the post has to be approved)

Thanks!

    static string[] Scopes = {  GmailService.Scope.MailGoogleCom,
                                GmailService.Scope.GmailSettingsBasic,
                                GmailService.Scope.GmailSettingsSharing,
                                GmailService.Scope.GmailModify};

    /// <summary>
    /// Gets default send as email address from user's gmail - throws error if valid domain is not used as default sendAs
    /// </summary>
    /// <param name="primaryEmailAddress">User's email address to use to impersonate</param>
    /// <param name="excludedDomains">Domains to exclude in the results - example: @xyz.org</param>
    /// <returns>default SendAs email address</returns>
    public static string GetDefaultSendAs(string primaryEmailAddress, string[] excludedDomains)
    {
        string retVal = string.Empty;
        GmailService service = new GmailService(new BaseClientService.Initializer()
        {
            HttpClientInitializer = 
                Auth.GetServiceAccountAuthorization
                    (scopes: Scopes, clientSecretFilePath: Constant.ClientSecretFilePath, impersonateAs: primaryEmailAddress)
        });


        var result = service.Users.Settings.SendAs.List("me").Execute();

        SendAs s = result.SendAs.First(e => e.IsDefault == true);
        bool incorrectSendAs = false;

        if (s != null)
        {
            foreach (string domain in excludedDomains)
            {
                // Check if email ends with domain
                if (s.SendAsEmail.ToLower().EndsWith("@" + domain.TrimStart('@'))) // removes @ and adds back - makes sure to domain start with @.
                {
                    incorrectSendAs = true;
                }
            }             
        }

        if (s != null && !incorrectSendAs)
            retVal = s.SendAsEmail;
        else
            throw new Exception($"{primaryEmailAddress}, valid default SendAs email not set."); 

        System.Threading.Thread.Sleep(10);

        return retVal;
    }

Auth Code:

class Auth
{
    internal static ServiceAccountCredential GetServiceAccountAuthorization(string[]scopes, string clientSecretFilePath, string impersonateAs = "[email protected]")
    {
        ServiceAccountCredential retval;

        if (impersonateAs == null || impersonateAs == string.Empty)
        {
            throw new Exception("Please provide user to impersonate");
        }
        else
        {

            using (var stream = new FileStream(clientSecretFilePath, FileMode.Open, FileAccess.Read))
            {
                retval = GoogleCredential.FromStream(stream)
                                             .CreateScoped(scopes)
                                             .CreateWithUser(impersonateAs)
                                             .UnderlyingCredential as ServiceAccountCredential;
            }
        }

        return retval;
    }

API client access: API client access


Solution

  • Note on batching

    First I am gong to ask why you are using batching. If you are hoping it will save you on quota usage it wont batching is effected by the same quota usage as normal api calls. The only help batching will give you would be in sending fewer HTTP calls and there by spending things up a little.

    Each HTTP connection that your client makes results in a certain amount of overhead. The some Google APIs supports batching, to allow your client to put several API calls into a single HTTP request.

    The HTTP headers for the outer batch request, except for the Content- headers such as Content-Type, apply to every request in the batch. If you specify a given HTTP header in both the outer request and an individual call, then the individual call header's value overrides the outer batch request header's value. The headers for an individual call apply only to that call.

    For example, if you provide an Authorization header for a specific call, then that header applies only to that call. If you provide an Authorization header for the outer request, then that header applies to all of the individual calls unless they override it with Authorization headers of their own.

    Authorization

    When you authorize to an api that authorization is for a single user.

    GmailService service = new GmailService(new BaseClientService.Initializer()
        {
            HttpClientInitializer = 
                Auth.GetServiceAccountAuthorization
                    (scopes: Scopes, clientSecretFilePath: Constant.ClientSecretFilePath, impersonateAs: primaryEmailAddress)
        });
    

    The above service will have access to only that one users data the user which you are impersonating.

    Anwser

    Is there a way to do a batch request to get SendAs emails from multiple or all users?

    No there is not. As you can read from above the authorization header of a batch request covers all of the items in the batch. The authorization header created sent with the GmailService for your batch request is only going to cover a single user.