GMAIL API sending email with attachment in c# - gmail-api

I need help with sending email w/attachment using Gmail Api in c#.
I have read Google website on sending emails with attachment but the example is in java.

Its too late for the answer, but posting it in case anyone needs it:)
Need MimeKit library for this: can be installed from NuGet.
Code:
public void SendHTMLmessage()
{
//Create Message
MailMessage mail = new MailMessage();
mail.Subject = "Subject!";
mail.Body = "This is <b><i>body</i></b> of message";
mail.From = new MailAddress("fromemailaddress#gmail.com");
mail.IsBodyHtml = true;
string attImg = "C:\\Documents\\Images\\Tulips.jpg OR Any Path to attachment";
mail.Attachments.Add(new Attachment(attImg));
mail.To.Add(new MailAddress("toemailaddress.com.au"));
MimeKit.MimeMessage mimeMessage = MimeKit.MimeMessage.CreateFromMailMessage(mail);
Message message = new Message();
message.Raw = Base64UrlEncode(mimeMessage.ToString());
//Gmail API credentials
UserCredential credential;
using (var stream =
new FileStream("client_secret.json", FileMode.Open, FileAccess.Read))
{
string credPath = System.Environment.GetFolderPath(
System.Environment.SpecialFolder.Personal);
credPath = Path.Combine(credPath, ".credentials/gmail-dotnet-quickstart2.json");
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scope,
"user",
CancellationToken.None,
new FileDataStore(credPath, true)).Result;
Console.WriteLine("Credential file saved to: " + credPath);
}
// Create Gmail API service.
var service = new GmailService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
//Send Email
var result = service.Users.Messages.Send(message, "me/OR UserId/EmailAddress").Execute();
}
Scope can be:
GmailSend or GmailModify
static string[] Scope = { GmailService.Scope.GmailSend };
static string[] Scope = { GmailService.Scope.GmailModify };
Base64UrlEncode function:
private string Base64UrlEncode(string input)
{
var inputBytes = System.Text.Encoding.UTF8.GetBytes(input);
return Convert.ToBase64String(inputBytes)
.Replace('+', '-')
.Replace('/', '_')
.Replace("=", "");
}

I have an example in VB.net. GMail API Emails Bouncing.
Google page provides examples in Java and Python only. The objects being used in the Java example are not available in .Net version of API. It is not possible to translate those examples.
Fortunately, it is quite easy to do the same in C#/VB. Just use plain old Net.Mail.MailMessage to create a message including attachments, then use MimeKit (NuGet it) to convert the message into string and pass the string (after encoding Base64) to "Raw" field of message.send of Gmail API.

There's nothing particular to sending an attachment with the Gmail API. Either way the Gmail API message.send() takes a full RFC822 email message in the message.raw field (urlsafe base64 encoded). The main trick is building up such an RFC822 email message string in your language. I imagine there are some MIME message librarys in C# and that's the main issue is finding those libraries. I don't do C# but javax.internet.mail.MimeMessage works well in java and the 'email' module is good for python.
This other post seems relevant:
How to send multi-part MIME messages in c#?

string[] Scopes = { GmailService.Scope.GmailSend };
string ApplicationName = "Gmail API App";
public GmailForm()
{
InitializeComponent();
SendHTMLmessage();
}
string Base64UrlEncode(string input)
{
var data = Encoding.UTF8.GetBytes(input);
return Convert.ToBase64String(data).Replace("+", "-").Replace("/", "_").Replace("=", "");
}
public void SendHTMLmessage()
{
//Create Message
MailMessage mail = new MailMessage();
mail.Subject = "Subject!";
mail.Body = "This is <b><i>body</i></b> of message";
mail.From = new MailAddress("youremail#gmail.com");
mail.IsBodyHtml = true;
string attImg = "C:\\attachment.pdf";
mail.Attachments.Add(new Attachment(attImg));
mail.To.Add(new MailAddress("receiver#mail.com"));
MimeKit.MimeMessage mimeMessage = MimeKit.MimeMessage.CreateFromMailMessage(mail);
var msg = new Google.Apis.Gmail.v1.Data.Message();
msg.Raw = Base64UrlEncode(mimeMessage.ToString());
//Gmail API credentials
UserCredential credential;
using (var stream =new FileStream(Application.StartupPath + #"/credentials.json", FileMode.Open, FileAccess.Read))
{
string credPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
credPath = Path.Combine(credPath, ".credentials/gmail-dotnet-quickstart2.json");
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(GoogleClientSecrets.Load(stream).Secrets,Scopes,"user",CancellationToken.None,new FileDataStore(credPath, true)).Result;
Console.WriteLine("Credential file saved to: " + credPath);
}
// Create Gmail API service.
var service = new GmailService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
//Send Email
var result = service.Users.Messages.Send(msg, "me").Execute();
MessageBox.Show("Your email has been successfully sent !", "Message", MessageBoxButtons.OK, MessageBoxIcon.Information);
}

Related

Unable to send email via Microsoft Graph API with Delegated Permission

I created a C# console application to send email using Microsoft Graph API. On adding Mail.Send Application Permission, it works fine. But, because of company requirements, I was asked to use Mail.Send Delegated Permission instead and with that permission I don't see it working and I see this error:
Are there any steps I should consider doing after adding Mail.Send Delegated Permission in order to get this working?
Here is my code:
static void Main(string[] args)
{
// Azure AD APP
string clientId = "<client Key Here>";
string tenantID = "<tenant key here>";
string clientSecret = "<client secret here>";
Task<GraphServiceClient> callTask = Task.Run(() => SendEmail(clientId, tenantID, clientSecret));
// Wait for it to finish
callTask.Wait();
// Get the result
var astr = callTask;
}
public static async Task<GraphServiceClient> SendEmail(string clientId, string tenantID, string clientSecret)
{
var confidentialClientApplication = ConfidentialClientApplicationBuilder
.Create(clientId)
.WithTenantId(tenantID)
.WithClientSecret(clientSecret)
.Build();
var authProvider = new ClientCredentialProvider(confidentialClientApplication);
var graphClient = new GraphServiceClient(authProvider);
var message = new Message
{
Subject = subject,
Body = new ItemBody
{
ContentType = BodyType.Text,
Content = content
},
ToRecipients = new List<Recipient>()
{
new Recipient
{
EmailAddress = new EmailAddress { Address = recipientAddress }
}
}
};
var saveToSentItems = true;
await _graphClient.Users[<userprincipalname>]
.SendMail(message, saveToSentItems)
.Request()
.PostAsync();
return graphClient;
}
UPDATE:
Based on below answer, I updated code as follows:
var publicClientApplication = PublicClientApplicationBuilder
.Create("<client-id>")
.WithTenantId("<tenant-id>")
.Build();
var authProvider = new UsernamePasswordProvider(publicClientApplication);
var secureString = new NetworkCredential("", "<password>").SecurePassword;
User me = await graphClient.Me.Request()
.WithUsernamePassword("<username>", secureString)
.GetAsync();
I enabled "Allow public client flows" to fix an exception.
And now I see another exception: Insufficient privileges to complete the operation.
What am I missing?
UPDATE: Currently I see this exception with no changes in the code:
The code you provided shows you use client credential flow to do the authentication. When you use Mail.Send Application permission, use client credential flow is ok. But if you use Mail.Send Delegated permission, we can not use client credential. You should use username/password flow to do authentication.
=================================Update===================================
Below is my code:
using Microsoft.Graph;
using Microsoft.Graph.Auth;
using Microsoft.Identity.Client;
using System;
using System.Collections.Generic;
using System.Security;
namespace ConsoleApp34
{
class Program
{
static async System.Threading.Tasks.Task Main(string[] args)
{
Console.WriteLine("Hello World!");
var publicClientApplication = PublicClientApplicationBuilder
.Create("client id")
.WithTenantId("tenant id")
.Build();
string[] scopes = new string[] { "mail.send" };
UsernamePasswordProvider authProvider = new UsernamePasswordProvider(publicClientApplication, scopes);
GraphServiceClient graphClient = new GraphServiceClient(authProvider);
var 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 = "to email address"
}
}
}
};
var securePassword = new SecureString();
foreach (char c in "your password")
securePassword.AppendChar(c);
var saveToSentItems = true;
await graphClient.Me
.SendMail(message, saveToSentItems)
.Request().WithUsernamePassword("your email", securePassword)
.PostAsync();
}
}
}
The reason for your error message Insufficient privileges to complete the operation is you use the code:
User me = await graphClient.Me.Request()
.WithUsernamePassword("<username>", secureString)
.GetAsync();
This code is used to get the user(me)'s information but not send email, you haven't added the permission to the app. So it will show Insufficient privileges to complete the operation. Please remove this code and use the code block in my code instead:
await graphClient.Me.SendMail(message, saveToSentItems)
.Request().WithUsernamePassword("your email", securePassword)
.PostAsync();
==============================Update2====================================

Hack to upload a file from Java backend to a remote server over HTTP using Rest API.

My file resides on some location on my machine say C://users//abc.txt and i want to write a java program to transfer this file using REST API over HTTP. I used MockHttpServelet Request to create the request, but somehow i am unable to transfer the file
Use HttpClient:
String url = "http://localhost:8080/upload"; // Replace with your target 'REST API' url
String filePath = "C://users//abc.txt";
CloseableHttpClient httpClient = HttpClients.createDefault();
try {
HttpPost httpPost = new HttpPost(url);
FileEntity entity = new FileEntity(new File(filePath), ContentType.TEXT_PLAIN);
httpPost.setEntity(entity);
HttpResponse httpResponse = httpClient.execute(httpPost);
System.out.println(httpResponse.getStatusLine().getStatusCode()); // Check HTTP code
} finally {
httpClient.close();
}
With Authentication:
String url = "http://localhost:8080/upload"; // Replace with your target 'REST API' url
String filePath = "C://users//abc.txt";
String username = "username"; // Replace with your username
String password = "password"; // Replace with your password
RequestConfig requestConfig =
RequestConfig.custom().
setAuthenticationEnable(true).
build();
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(
AuthScope.ANY,
new UsernamePasswordCredential(username, password));
CloseableHttpClient httpClient =
HttpClients.custom().
setDefaultRequestConfig(requestConfig).
setDefaultCredentialsProvider(credentialsProvider).
build();
try {
HttpPost httpPost = new HttpPost(url);
FileEntity entity = new FileEntity(new File(filePath), ContentType.TEXT_PLAIN);
httpPost.setEntity(entity);
HttpResponse httpResponse = httpClient.execute(httpPost);
System.out.println(httpResponse.getStatusLine().getStatusCode()); // Check HTTP code
} finally {
httpClient.close();
}
String location="C:\\Usersabc.img";
Path path = Paths.get(location);
String name=location.substring(location.lastIndexOf("\\")+1);
MultipartEntity multipart= new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
try {
multipart.addPart("image", new ByteArrayBody(Files.readAllBytes(path), ContentType.APPLICATION_OCTET_STREAM.getMimeType(),name));
}
catch (IOException ex) {
// TODO Auto-generated catch block
ex.printStackTrace();
}

How to send mail automatically in ng-click?

I'm using angularjs 1.4.8 in Visual Studio 2013. I want to send email to xxxx# xxxx.com with message "Your registration completed" automatically after button has been clicked. How can I send email by angularjs?
[HttpPut]
[Route("api/SendMail")]
protected void sendmail()
{
var fromAddress = "xxxk#xxxxx.com";
var toAddress = "rrrr#rrr.com";
const string fromPassword = "workufs1234";
MailMessage mailMessage = new MailMessage(fromAddress, toAddress);
mailMessage.To.Add(toAddress);
mailMessage.Subject = "Documents";
string messge = "hellooooo";
string tempmsg = "";
var messg = #"<html><body><br />Dear ss ,<br /><br /> <br />";
mailMessage.To.Add(toAddress);
string html = messg.ToString();
AlternateView altView = AlternateView.CreateAlternateViewFromString(html, null, MediaTypeNames.Text.Html);
MailMessage mail = new MailMessage();
mailMessage.AlternateViews.Add(altView);
mailMessage.Body = messg.ToString();
mailMessage.IsBodyHtml = true;
SmtpClient mailSender = new SmtpClient("162.222.225.82"); //use this if you are in the development server
mailSender.Host = "smtp.gmail.com";
mailSender.Port = 587;
mailSender.EnableSsl = true;
mailSender.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network;
mailSender.Credentials = new NetworkCredential(fromAddress, fromPassword);
mailSender.Timeout = 40000;
mailSender.Send(mailMessage);
}
How can test this using postman. is this httppost or put or?
HTML code:
<button ng-click="sendMail()"></button>
Controller:
$scope.message = {} // contact info goes here
$scope.sendMail = function(){
var mail = 'mailto:mohamed#labouardy.com?subject=' + $scope.message.name +
'&body=' + $scope.message.content;
$window.open(mail);
}
I think you will need a server side to do this properly. (PHP / NodeJS, ...)
On my NodeJS server, I'm using 'nodemailer', which works perfectly.
https://www.npmjs.com/package/nodemailer
Hope it helps.

Swagger documentation for BeanParam

I'm trying to document one of my java APIs (implemented in Apache CXF) using Swagger, that receives it's parameters using a Bean Param. Something like:
#GET
#Produces({SemanticMediaType.JSON_LD, MediaType.APPLICATION_JSON_VALUE})
#ApiOperation(value = "Retrieves Themes", position = 0)
#ApiResponses(value = {#ApiResponse(code = 200,
message = "Retrieval was successful"), #ApiResponse(code = 403,
message = "Missing or invalid x-business-group-id header"), #ApiResponse(code = 500,
message = "Internal server error")})
public Response get(#QueryParam(URI_PARAM_NAME) String uri,
final #ApiParam #Valid #BeanParam ThemeParams themeParams) { ... }
I read that Swagger already implements support for BeanParams, but when I try to run it, in swagger-ui, I only see one parameter called "body" and a text field, nothing related to the contents of my BeanParam.
Can somebody provide some assistance with this?
This is a bit old, but for those who are having the same issues, here is what I found helped.
If you are using the DefaultJaxrsConfig, change it to JerseyJaxrsConfig.
If you are linking to swagger-jersey-jaxrs_..., change it to swagger-jersey2-jxsrs_...
You can refer to.
#POST
#Path("/users")
#ApiOperation(value = "vdc", position = 1, notes = "vdc")
#ApiResponses(value = {
#ApiResponse(code = 200, message = "OK",response=UserCreateResponse.class),
#ApiResponse(code = 30601, message = "'httpcode': 400 'Errormsg': Request Params Not Valid"),
#ApiResponse(code = 30602, message = "'httpcode':404 'Errormsg': Data Required Not Found"),
#ApiResponse(code = 30603, message = "'httpcode':405 'Errormsg': Method Not Allowed"),
#ApiResponse(code = 30604, message = "'httpcode':408 'Errormsg': Request Time Expires Timeout"),
#ApiResponse(code = 30605, message = "'httpcode':500 'Errormsg': Internal Server Error") })
public Response createUsersWithArrayInput(
#ApiParam(value = "ID", name = "platform_id", required = true) #QueryParam(value = "platform_id") String platformId,
#ApiParam(value="body",name="user",required=true)UserCreate userCreate) {}
UserCreate.java
#ApiModel("UserCreate")
public class UserCreate {
#ApiModelProperty(value="VDC Id",required=false)
#JsonStringSchema(optional=true,description="VDC Id")
private String vdcId;
#ApiModelProperty(value="description",required=true)
private String name;
#ApiModelProperty(value="description",required=false)
private String password;
}

Send emails with attachments in salesforce via sendgrid

I am trying to generate a pdf and attach to an email and send it.
I am using salesforce and sendgrid.
I am able to send emails but the problem is when I try to attach the pdf, the email is with the attachment, but this is broken, the file is not empty, but the pdf says is broken (I think is a problem of conversion)
here is the code
Messaging.EmailFileAttachment efa = new Messaging.EmailFileAttachment();
PageReference pdf = Page.include_attachment;
pdf.getParameters().put('id', 'xxxxxxxxxxxxxxxxxx');
blob fileBody = pdf.getContentAsPDF();
efa.setBody(fileBody);
efa.setFileName('test.pdf');
efa.setContentType('application/pdf;charset=UTF-8;');
send('xxxxx#xxxx.com','Test','Body Test', fileBody);
I tryied using
pdf.getContentAsPDF();
and
pdf.getContent();
but the result is the same.
Send method
public static void send(String emailRecipient, String emailSubject, String emailBody, Blob att){
Boolean success=true;
//construct the body of the request
String requestBody='';
requestBody += 'to='+EncodingUtil.urlEncode(emailRecipient,'UTF-8');
requestBody += '&from='+EncodingUtil.urlEncode(user.Email,'UTF-8');
requestBody += '&fromname='+EncodingUtil.urlEncode(user.Name,'UTF-8');
requestBody += '&subject='+EncodingUtil.urlEncode(emailSubject,'UTF-8');
requestBody += '&text='+EncodingUtil.urlEncode(emailBody.trim(),'UTF-8');
requestBody += '&html='+EncodingUtil.urlEncode(emailBody.trim(),'UTF-8');
requestBody += '&api_user=xxxxx';
requestBody += '&api_key=xxxxx';
requestBody += '&files[attachment.pdf]=#'+ EncodingUtil.base64Encode(att);
//construct request
HttpRequest req = new HttpRequest();
req.setEndpoint('https://sendgrid.com/api/mail.send.json');
req.setMethod('POST');
req.setBody(requestBody);
try{
//send request
Http h = new Http();
HttpResponse res = h.send(req);
//check response
String status = res.getStatus();
if(status.toUpperCase()=='OK'){
success=true;
}
else{
success=false;
}
}
catch(Exception e){
success=false;
}
}
Thank you
There is now a library/devtoolkit to do this for you. At the time of this writing it is in beta, but it is working. Disclaimer: I work at SendGrid and have just recently developed the library.
sendgrid-apex
You can rewrite your code to:
...
Blob att = pdf.getContentAsPDF();
public static void send(String emailRecipient, String emailSubject, String emailBody, Blob att){
SendGrid sendgrid = new SendGrid('username', 'password');
SendGrid.email email = new SendGrid.Email();
email.addTo(emailRecipient);
email.setFrom(user.Email);
email.setFromName(user.Name);
email.setSubject(emailSubject);
email.setText(emailBody.trim());
email.setHtml(emailBody.trim());
email.addAttachmentStream("attachment.pdf", att);
String response = sendgrid.send(email);
}

Resources