Click here to Skip to main content
14,271,889 members
   

ASP.NET

 
QuestionServer-side Blazor and IE11 Pin
MSBassSinger2-Aug-19 5:57
professionalMSBassSinger2-Aug-19 5:57 
Question.Net Core V2.2 - Sending email or gmail using OAuth2 or secure settings in Gmail in the background without browser auth Pin
jkirkerx1-Aug-19 12:28
professionaljkirkerx1-Aug-19 12:28 
AnswerRe: .Net Core V2.2 - Sending email or gmail using OAuth2 or secure settings in Gmail in the background without browser auth Pin
Afzaal Ahmad Zeeshan1-Aug-19 14:37
mveAfzaal Ahmad Zeeshan1-Aug-19 14:37 
GeneralRe: .Net Core V2.2 - Sending email or gmail using OAuth2 or secure settings in Gmail in the background without browser auth Pin
jkirkerx2-Aug-19 6:50
professionaljkirkerx2-Aug-19 6:50 
GeneralRe: .Net Core V2.2 - Sending email or gmail using OAuth2 or secure settings in Gmail in the background without browser auth Pin
jkirkerx2-Aug-19 11:45
professionaljkirkerx2-Aug-19 11:45 
AnswerThought I had it, Failed to open browser when running in Docker Container Pin
jkirkerx2-Aug-19 12:50
professionaljkirkerx2-Aug-19 12:50 
AnswerFigured it out [solved] Pin
jkirkerx3-Aug-19 13:44
professionaljkirkerx3-Aug-19 13:44 
GeneralRe: Figured it out [solved] - New Code Pin
jkirkerx5-Aug-19 13:22
professionaljkirkerx5-Aug-19 13:22 
Really just a reference for me in case I need to dig it up again.

But I spent the morning refactoring the previous code. Took some time because documentation was limited to just 1 post on GitHub of a user suggesting a change to the API. So this takes a service Json file created on Google Cloud or API when you create a Service Account using the Json option, and not the PFM option, and loads the file from the root of the project directly, and creates a ServiceAccountCredential. I added a User "user: me@mydomain.com" to the Google Service Json file in which the Google API didn't seem to mind it being there. The user is my email address required for the Initializer. The MAILSERVER really just contains the name of the Google Service File. So ms.GoogleServiceFile can be replaced with the name of your file.

Not too happy with the double stream, or the use of File.ReadAllTextAsync, because I needed the user parameter that I added and the GoogleCredential.FromStream would not pass it along. I thought about making a copy of the stream, or rewinding it back to 0. The user field is in the ServiceCredentials, perhaps I just need to rename user to something else that can be read.

So far so good; it works in my Debug Docker Linux container and in my production Docker container as well.
Hope this helps the next guy looking to do the same when Google discontinues "Use less secure settings" in Gmail when they remove the option next October.

This should be backwards compatible with MVC, and I wrote this for .Net Core V2.2+ using NeGet
Google.Apis.Gmail.v1.40.2.1635 GitHub - googleapis/google-api-dotnet-client: Google APIs Client Library for .NET
MailKit V2.2
MimeKit V2.2 MimeKit
public static async Task<ServiceAccountCredential> Create_GoogleCredentialsWithAccessToken(MAILSERVER ms)
{
    ServiceAccountCredential credentials = null;<br />
    var serviceStream = await File.ReadAllTextAsync(ms.GoogleServiceFile);
    var parameters = new NewtonsoftJsonSerializer().Deserialize<GoogleServiceApi>(serviceStream);

    // Proceed as normal loading the credentials. 
    using (var stream = new FileStream(ms.GoogleServiceFile, FileMode.Open, FileAccess.Read))
    {
        ServiceAccountCredential original = (ServiceAccountCredential)
        GoogleCredential.FromStream(stream).UnderlyingCredential;

        var initializer = new ServiceAccountCredential.Initializer(original.Id)
        {
            User = parameters.user,
            ProjectId = parameters.project_id,
            Key = original.Key,
            Scopes = new[] { GmailService.Scope.MailGoogleCom, GmailService.Scope.GmailSend }
        };
        credentials = new ServiceAccountCredential(initializer);

        if (await credentials.RequestAccessTokenAsync(CancellationToken.None))
        {
            var service = new GmailService(
                new BaseClientService.Initializer()
                {
                    HttpClientInitializer = credentials
                }
            );
        }
    }

    return credentials;
}
public static async Task<SendEmailCompletedEventArgs> Send_GmailServiceAsync(ServiceAccountCredential serviceCredentials, MimeMessage message, int retryCount)
{
    var currentTry = 0;
    while ((currentTry < retryCount))
    {
        try
        {
            using (var client = new SmtpClient())
            {
                client.Connect("smtp.gmail.com", 587, SecureSocketOptions.StartTls);

                var oauth2 = new SaslMechanismOAuth2(serviceCredentials.User, serviceCredentials.Token.AccessToken);
                client.Authenticate(oauth2);

                await client.SendAsync(message);
                client.Disconnect(true);
            }

            return new SendEmailCompletedEventArgs(null, false, null, currentTry);
        }
        catch (Exception ex)
        {
            currentTry++;
            if ((currentTry >= retryCount))
            {
                return new SendEmailCompletedEventArgs(ex, true, null, currentTry);
            }
        }

    }

    //  Code should never reach here, but without this line you'll get a BC42105 warning:
    return new SendEmailCompletedEventArgs(null, true, null, currentTry);
}

Class to code against for NewtonSoftJsonSerializer
public class GoogleServiceApi
{
    public string type { get; set; }
    public string user { get; set; }
    public string project_id { get; set; }
    public string private_key_id { get; set; }
    public string private_key { get; set; }
    public string client_email { get; set; }
    public string client_id { get; set; }
    public string auth_uri { get; set; }
    public string token_uri { get; set; }
    public string auth_provider_x509_cert_url { get; set; }
    public string client_x509_cert_url { get; set; }
}
If it ain't broke don't fix it
Discover my world at jkirkerx.com

QuestionInsert Date Interval Pin
Bartt_dmr25-Jul-19 10:31
memberBartt_dmr25-Jul-19 10:31 
AnswerRe: Insert Date Interval Pin
Richard Deeming25-Jul-19 10:49
mveRichard Deeming25-Jul-19 10:49 
QuestionObject reference not set to an instance of an object. Pin
Darwin Ahmed21-Jul-19 12:06
memberDarwin Ahmed21-Jul-19 12:06 
AnswerRe: Object reference not set to an instance of an object. Pin
phil.o21-Jul-19 19:50
mvephil.o21-Jul-19 19:50 
AnswerRe: Object reference not set to an instance of an object. Pin
ZurdoDev24-Jul-19 9:10
professionalZurdoDev24-Jul-19 9:10 
QuestionChange Value of HttpContext.Current.User Pin
MadDashCoder21-Jul-19 4:26
memberMadDashCoder21-Jul-19 4:26 
AnswerRe: Change Value of HttpContext.Current.User Pin
Richard MacCutchan21-Jul-19 6:42
protectorRichard MacCutchan21-Jul-19 6:42 
AnswerRe: Change Value of HttpContext.Current.User Pin
Afzaal Ahmad Zeeshan21-Jul-19 6:51
mveAfzaal Ahmad Zeeshan21-Jul-19 6:51 
AnswerRe: Change Value of HttpContext.Current.User Pin
ZurdoDev24-Jul-19 9:12
professionalZurdoDev24-Jul-19 9:12 
QuestionQuery timing out, help please!!! Pin
samflex19-Jul-19 8:38
membersamflex19-Jul-19 8:38 
AnswerRe: Query timing out, help please!!! Pin
ZurdoDev19-Jul-19 10:14
professionalZurdoDev19-Jul-19 10:14 
AnswerRe: Query timing out, help please!!! Pin
David Mujica22-Jul-19 7:59
memberDavid Mujica22-Jul-19 7:59 
QuestionForm Designer Pin
wrightyrx715-Jul-19 4:58
memberwrightyrx715-Jul-19 4:58 
AnswerRe: Form Designer Pin
Mycroft Holmes15-Jul-19 11:26
memberMycroft Holmes15-Jul-19 11:26 
GeneralRe: Form Designer Pin
wrightyrx715-Jul-19 11:33
memberwrightyrx715-Jul-19 11:33 
GeneralRe: Form Designer Pin
Mycroft Holmes15-Jul-19 14:08
memberMycroft Holmes15-Jul-19 14:08 
QuestionGetting undefined in Cascading DropDownList In ASP.Core MVC ? Pin
Abdalla Ben Omran11-Jul-19 9:29
memberAbdalla Ben Omran11-Jul-19 9:29 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.