asp.net core web api using smtp with Oauth2 for gmail as well as outlook

Rajesh Kola 0 Reputation points
2025-03-24T15:57:27.27+00:00

Hi,

I am using ASP.NET Core Web API 8. I need to create a sample program for sending emails using Gmail SMTP with OAuth2 (web application flow), as well as Outlook (web application flow). Can you provide any sample code, documentation, and screenshots?

Developer technologies ASP.NET ASP.NET Core
0 comments No comments
{count} votes

2 answers

Sort by: Most helpful
  1. Bruce (SqlWork.com) 77,686 Reputation points Volunteer Moderator
    2025-03-24T23:34:53.78+00:00

    for outlook you use the graphapi:

    https://learn.microsoft.com/en-us/graph/api/resources/mail-api-overview?view=graph-rest-1.0

    for google smtp, you will need a 3rd party (Microsoft does not have one) smtp library that supports oauth. popular open source project:

    https://github.com/jstedfast/MailKit

    0 comments No comments

  2. Anonymous
    2025-04-04T02:35:23.2+00:00

    as well as Outlook (web application flow)

    Hi Rajesh, just like what Bruce mentioned, we need to use Graph API to send email. I will explain this in detail.

    First of all, when we hope our web API to be able to send emails, it doesn't mean we only require an Outlook email account, we must have a Microsoft account which has email license for your account, such as M365 E3 license. It will ensure you can use user@your_tenant.onmicrosoft.com account to send email to some other users. This is because Microsoft auth can't bypass external SMTP service, for example, when you sign in with your Microsoft account, you can't send email on-behalf-of your google account. The same for outlook accounts, even if you can use your outlook account to sign as Microsoft account, you still have to assign a license to your outlook account. This is because when you sign up Microsoft with your outlook account, in Azure tenant, it creates another Microsoft account for you which format shall be username_outlook.com#EXT#@tenantName.onmicrosoft.com.

    Assuming you already have such a Microsoft account now, we can use Graph API to help send email on behalf of this account, but we need to authenticate Graph API ahead, which requiring OAuth2.0. You are now working on a web API project, so that we have 2 approaches to authenticate Graph API: using Client Credential Flow to authenticate as the application itself (requires Application type API permission) and using On-Behalf-Of flow to authenticate the user (requires Delegated type API permission).

    User's image

    Then here's the codes. For client credential flow, it will be a little bit easier:

    using Azure.Identity;
    using Microsoft.Graph;
    
    var requestBody = new SendMailPostRequestBody
    {
    	Message = new Message
    	{
    		Subject = "Meet for lunch?",
    		Body = new ItemBody
    		{
    			ContentType = BodyType.Text,
    			Content = "The new cafeteria is open.",
    		},
    		ToRecipients = new List<Recipient>
    		{
    			new Recipient
    			{
    				EmailAddress = new EmailAddress
    				{
    					Address = "******@contoso.com",
    				},
    			},
    		},
    		CcRecipients = new List<Recipient>
    		{
    			new Recipient
    			{
    				EmailAddress = new EmailAddress
    				{
    					Address = "******@contoso.com",
    				},
    			},
    		},
    	},
    	SaveToSentItems = false,
    };
    var scopes = new[] { "https://graph.microsoft.com/.default" };
    var tenantId = "tenant_id";
    var clientId = "azure_ad_app_client_id";
    var clientSecret = "client_secret_for_the_azuread_app";
    var clientSecretCredential = new ClientSecretCredential(tenantId, clientId, clientSecret);
    var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
    var res = await graphClient.Users["user_id_which_you_wanna_used_for_sending_email"].SendMail.PostAsync(requestBody);
    

    If you hope to create an API that any user can call it, and then send email on behalf of the user himself, then you should use on behalf of flow. It shall be a little bit complex. You need to secure your API ahead. Then your Program.cs shall have codes below:

    builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"))
        .EnableTokenAcquisitionToCallDownstreamApi()
        .AddMicrosoftGraph(builder.Configuration.GetSection("DownstreamApi"))//require Microsoft.Identity.Web.GraphServiceClient package
        .AddInMemoryTokenCaches();
    

    You also need to have below configuration in appsettings.

    "AzureAd": {
      "Instance": "https://login.microsoftonline.com/",
      "ClientId": "azure_ad_app_client_id",
      "ClientSecret": "client_secret_for_the_azuread_app",
      "Domain": "tenant_id",
      "TenantId": "tenant_id",
      "Scopes": "Your custom API permission name, e.g: Tiny.Read",
      "CallbackPath": "/signin-oidc"
    },
    

    I used below nuget packages:

    <ItemGroup>
      <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.11" NoWarn="NU1605" />
      <PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="8.0.11" NoWarn="NU1605" />
      <PackageReference Include="Microsoft.Identity.Web" Version="3.2.0" />
      <PackageReference Include="Microsoft.Identity.Web.DownstreamApi" Version="3.2.0" />
      <PackageReference Include="Microsoft.Identity.Web.GraphServiceClient" Version="3.5.0" />
      <PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
    </ItemGroup>
    

    Now you can inject Graph API SDK into your Controller and send email.

    [Authorize]
    [ApiController]
    [Route("[controller]")]
    [RequiredScope(RequiredScopesConfigurationKey = "AzureAd:Scopes")]
    public class WeatherForecastController : ControllerBase
    {
    	private GraphServiceClient _graphServiceClient;// requires Microsoft.Identity.Web.GraphServiceClient package
    	public WeatherForecastController(GraphServiceClient graphServiceClient)
    	{
    		_graphServiceClient = graphServiceClient;
    	}
    	[HttpGet(Name = "GetWeatherForecast")]
    	public async Task<string>> GetAsync()
    	{
    		var requestBody = new SendMailPostRequestBody{};
    		var res = await _graphServiceClient.Me.SendMail.PostAsync(requestBody);
    		return "ok";
    	}
    }
    

    Now you need to get the variables required in your codes. You need to create Azure AD(know as Microsoft Entra now) application registration and grant required API permission. The detailed flow already included in the "secure your API" tutorial. Please note, after you added API permission, you also need to grant Admin consent. For Client credential flow, you don't need to expose your custom web api, you just need to add Application type Mail.Send permission, but for on-behalf-of flow, you also need to expose custom API and add it to API permission. This custom API permission is used in your client side application to generate access token. You need to add a valid access token into your request header to call your API, then the auth scheme in your API can use that token to authenticate Graph SDK. If you don't have a client app and just want to test your API, you can refer to this case.


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    Best regards,
    Tiny


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.