I have a system that sends emails with inline pictures. The problem is how Outlook 2013 displays the attachments. Can I update my code in a way that tells outlook not to display the paperclip icon seen here?
The idea is that I only want to display this icon when full sized pictures are attached. Not inline attachments.
Here's the code that generates the email. Create a basic console app, specify your To / mailserver / picture path, and run.
static void Main(string[] args)
{
Console.WriteLine("Prepping email message....");
var subject = "Test Subject With Inline";
var message = "<p>This is a test message.</p><br/><br/><p>[CompanyLogo]</p>";
var to = new List<string>();
to.Add("My.Name#company.com");
Console.WriteLine("Sending email message....");
if (SendMessageToFrom(subject, message, to, new List<string>()))
{
Console.WriteLine("Email sent! Check your inbox.");
}
else
{
Console.WriteLine("Error sending email!");
}
}
public static bool SendMessageToFrom(String subject, String message, List<String> to, List<String> cc)
{
try
{
// Construct the email
var sendMessage = new MailMessage()
{
IsBodyHtml = true,
From = new MailAddress("noreply#company.com"),
Subject = subject,
Body = message
};
if (sendMessage.Body.Contains("[CompanyLogo]"))
{
sendMessage.AlternateViews.Add(EmbedLogo(sendMessage.Body));
}
// Add the list of recipients
foreach (var recipient in to)
{
sendMessage.To.Add(recipient);
}
foreach (var recipient in cc)
{
sendMessage.CC.Add(recipient);
}
//Specify the SMTP server
var smtpServerName = "mailserver.company.com";
var mailClient = new SmtpClient(smtpServerName);
mailClient.Send(sendMessage);
return true;
}
catch
{
throw;
}
}
private static AlternateView EmbedLogo(string html)
{
var inline = new LinkedResource("img\\company-logo.jpg");
inline.ContentId = Guid.NewGuid().ToString();
html = html.Replace("[CompanyLogo]", string.Format(#"<img src='cid:{0}'/>", inline.ContentId));
var result = AlternateView.CreateAlternateViewFromString(html, null, System.Net.Mime.MediaTypeNames.Text.Html);
result.LinkedResources.Add(inline);
return result;
}
Update: Here's the code that did the trick:
private static MailMessage EmbedLogo(MailMessage mail)
{
var inline = new Attachment("img\\company-logo.jpg");
inline.ContentId = Guid.NewGuid().ToString();
inline.ContentDisposition.Inline = true;
inline.ContentDisposition.DispositionType = DispositionTypeNames.Inline;
mail.Body = mail.Body.Replace("[CompanyLogo]", string.Format(#"<img src='cid:{0}'/>", inline.ContentId));
mail.Attachments.Add(inline);
return mail;
}
And I also updated the main method to this:
if (sendMessage.Body.Contains("[CompanyLogo]"))
{
sendMessage = EmbedLogo(sendMessage);
}
Make sure your attachments have the Content-ID MIME header and the message's HTML body refers to them using the cid attribute : <img src="cid:xyz"> (where xyz is the value of the Content-ID MIME header).
Related
I'm trying to remove or exclude a couple specific e-mail addresses from the CC e-mail address list. How should I do this? Here is the function:
private void SendEmail(string emailTo, string subject, string body)
{
using (SmtpClient client = new SmtpClient(System.Configuration.ConfigurationManager.AppSettings["SmtpServerAddress"]))
{
MailMessage email = new MailMessage();
email.From = new MailAddress(GetUserEmail());
string emailCc = ConfigurationManager.AppSettings["EmailCc"];
foreach (var item in emailTo.Split(';'))
{
email.To.Add(new MailAddress(item.Trim()));
}
foreach (var item in emailCc.Split(';'))
{
email.CC.Add(new MailAddress(item.Trim()));
}
email.Subject = subject;
email.IsBodyHtml = true;
email.Body = body;
return;
}
}
You put the emails you don't want into an array:
var badEmails = new [] { "a#a.aa", "b#b.bb" }
Then you use LINQ to remove them from the split:
var ccList = emailCc.Split(';').Where(cc => !badEmails.Any(b => cc.IndexOf(b, System.StringComparison.InvariantCultureIgnoreCase) > -1));
Then you add those in ccList to your email
You can try with this if you know email:
foreach (var item in emailCc.Split(';'))
{
if (!new string[] { "bad#gmail.com", "uncle#sam.com", "stack#overflow.com"}.Contains(email))
{
email.CC.Add(new MailAddress(item.Trim()));
}
}
instead of if statement you can use regular expression if you want to exclude some email with specific pattern.
I have a feedback button in unity game, if the user clicks on it then it should launch an default email app with subject, email address filled already. I have done this in Android app but how to call it from unity?
Are there any other better approaches for feedback other than this?
What you are doing is plugin. You don't need plugin for this.
You can simply send email with:
void sendEmail(string toEmail, string emailSubject, string emailBody)
{
emailSubject = System.Uri.EscapeUriString(emailSubject);
emailBody = System.Uri.EscapeUriString(emailSubject);
Application.OpenURL("mailto:" + toEmail + "?subject=" + emailSubject + "&body=" + emailBody);
}
To send, call:
sendEmail("example#example.com", "Test", "This is a text\r\nAnother test\r\nAnd another text");
This will work on PC, Android and iOS. I don't know for Mac.
Now if you still want to use Android API's, you still don't need to make a plugin for this. You can use AndroidJavaObject and write your email code with Android API.
private static void SendMail(string subject, string body, bool useHTML)
{
using (var intentClass = new AndroidJavaClass("android.content.Intent"))
{
// intent = new Intent(Intent.ACTION_SEND);
using (var intentObject = new AndroidJavaObject("android.content.Intent", intentClass.GetStatic<string>("ACTION_SEND")))
{
// Setting text type
if (useHTML)
// intent.setType("text/html");
intentObject.Call<AndroidJavaObject>("setType", "text/html");
else
// intent.setType("message/rfc822");
intentObject.Call<AndroidJavaObject>("setType", "message/rfc822");
// intent.putExtra(Intent.EXTRA_SUBJECT, emailSubject);
intentObject.Call<AndroidJavaObject>("putExtra", intentClass.GetStatic<string>("EXTRA_SUBJECT"), subject);
// Setting emailBody
if (useHTML)
{
// intent.putExtra(Intent.EXTRA_TEXT, Html.fromHtml(emailBody));
using (var html = new AndroidJavaClass("android.text.Html"))
{
var htmlBody = html.CallStatic<AndroidJavaObject>("fromHtml", body);
intentObject.Call<AndroidJavaObject>("putExtra", intentClass.GetStatic<string>("EXTRA_TEXT"), htmlBody);
}
}
else
{
intentObject.Call<AndroidJavaObject>("putExtra", intentClass.GetStatic<string>("EXTRA_TEXT"), body);
}
using (var unity = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
{
using (var currentActivity = unity.GetStatic<AndroidJavaObject>("currentActivity"))
{
currentActivity.Call("startActivity", intentObject);
}
}
}
}
}
And to call it SendMail("test", "Message", false);. You can improve it and add more features to it. This last example was lifted from here.
#Programmer's (native-method) answer is correct; but when the user is prompted to select an app to send the email, there's a good chance the user will have the possibility to select apps other than e-mail apps; e.g. WhatsApp. We don't want this to happen. As stated in the docs the way we could ensure that only e-mail apps will be shown to the user, is to use Intent.ACTION_SENDTO and intent.setData(Uri.parse("mailto:").
private void SendMail(string subject, string body)
{
using (var intentClass = new AndroidJavaClass("android.content.Intent"))
{
// intent = new Intent(Intent.ACTION_SEND);
using (var intentObject = new AndroidJavaObject("android.content.Intent", intentClass.GetStatic<string>("ACTION_SENDTO")))
{
//intent.setData(Uri.parse("mailto:"));
var uriClass = new AndroidJavaClass("android.net.Uri");
var uriObject = uriClass.CallStatic<AndroidJavaObject>("parse", "mailto:");
intentObject.Call<AndroidJavaObject>("setData", uriObject);
// intent.putExtra(Intent.EXTRA_SUBJECT, emailSubject);
intentObject.Call<AndroidJavaObject>("putExtra", intentClass.GetStatic<string>("EXTRA_SUBJECT"), subject);
//intentObject.Call<AndroidJavaObject>("putExtra", intentClass.GetStatic<string>("EXTRA_EMAIL"), "youremail#abc.xyz");
string[] email = { "youremail#abc.xyz" };
intentObject.Call<AndroidJavaObject>("putExtra", intentClass.GetStatic<string>("EXTRA_EMAIL"), email);
// Setting emailBody
intentObject.Call<AndroidJavaObject>("putExtra", intentClass.GetStatic<string>("EXTRA_TEXT"), body);
using (var unity = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
{
using (var currentActivity = unity.GetStatic<AndroidJavaObject>("currentActivity"))
{
currentActivity.Call("startActivity", intentObject);
}
}
}
}
}
Replace youremail#abc.xyz with the e-mail you intend to send the e-mail to.
The question is, why do all this hassle instead of simply sending the e-mail like stated below:
void sendEmail(string toEmail, string emailSubject, string emailBody)
{
emailSubject = System.Uri.EscapeUriString(emailSubject);
emailBody = System.Uri.EscapeUriString(emailSubject);
Application.OpenURL("mailto:" + toEmail + "?subject=" + emailSubject +
"&body=" + emailBody);
}
You might want to add HTML or some non-Latin text (e.g. Japanese, Arabic) to your e-mail's body. using System.Uri.EscapeUriString is going to mess that up. In that case, the native method will be your method of choice.
On Button click you have to call:
public void OpenActivity()
{
var androidJC = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
var jo = androidJC.GetStatic<AndroidJavaObject>("currentActivity");
// Accessing the class to call a static method on it
var jc = new AndroidJavaClass("com.xyz.abc.StartActivity");
// Calling a Call method to which the current activity is passed
jc.CallStatic("Call", jo);
}
}
Replace it by your activity and package name
var jc = new AndroidJavaClass("com.xyz.abc.StartActivity");
I'm using MailKit library to handle emails, which has been working well. However, I'm trying to split emails into their constituent files a) Main email (no attachments) b) Individual attachment files, to store on the filesystem.
I can save the attachments individually, but can't seem to remove them from the email body code. I.e. they're getting saved along with the main email, so duplicating data. :/
I've tried:
foreach (MimePart part in inMessage.BodyParts)
{
if (part.IsAttachment)
{
// Remove MimePart < This function isn't available on the collection.
}
}
Have also tried:
var builder = new BodyBuilder();
foreach (MimePart part in inMessage.BodyParts)
{
if (!part.IsAttachment)
{
// Add MimeParts to collection < This function isn't available on the collection.
}
}
outMessage.Body = builder.ToMessageBody();
If anyone can help with this, I'd much appreciate it.
Solution implemented FYI:
private string GetMimeMessageOnly(string outDirPath)
{
MimeMessage message = (Master as fsEmail).GetMimeMessage();
if (message.Attachments.Any())
{
var multipart = message.Body as Multipart;
if (multipart != null)
{
while (message.Attachments.Count() > 0)
{
multipart.Remove(message.Attachments.ElementAt(0));
}
}
message.Body = multipart;
}
string filePath = outDirPath + Guid.NewGuid().ToString() + ".eml";
Directory.CreateDirectory(Path.GetDirectoryName(outDirPath));
using (var cancel = new System.Threading.CancellationTokenSource())
{
using (var stream = File.Create(filePath))
{
message.WriteTo(stream, cancel.Token);
}
}
return filePath;
}
And to get the attachments only:
private List<string> GetAttachments(string outDirPath)
{
MimeMessage message = (Master as fsEmail).GetMimeMessage();
List<string> list = new List<string>();
foreach (MimePart attachment in message.Attachments)
{
using (var cancel = new System.Threading.CancellationTokenSource())
{
string filePath = outDirPath + Guid.NewGuid().ToString() + Path.GetExtension(attachment.FileName);
using (var stream = File.Create(filePath))
{
attachment.ContentObject.DecodeTo(stream, cancel.Token);
list.Add(filePath);
}
}
}
return list;
}
You could retrieve all MimeParts that are attachments https://github.com/jstedfast/MimeKit/blob/master/MimeKit/MimeMessage.cs#L734 and then iterate over the all Multiparts and call https://github.com/jstedfast/MimeKit/blob/master/MimeKit/Multipart.cs#L468 for the attachments to remove.
The sample below makes a few assumptions about the mail e.g. there is only one Multipart some email client (Outlook) are very creative how mails are crafted.
static void Main(string[] args)
{
var mimeMessage = MimeMessage.Load(#"x:\sample.eml");
var attachments = mimeMessage.Attachments.ToList();
if (attachments.Any())
{
// Only multipart mails can have attachments
var multipart = mimeMessage.Body as Multipart;
if (multipart != null)
{
foreach(var attachment in attachments)
{
multipart.Remove(attachment);
}
}
mimeMessage.Body = multipart;
}
mimeMessage.WriteTo(new FileStream(#"x:\stripped.eml", FileMode.CreateNew));
}
Starting with MimeKit 0.38.0.0, you'll be able to use a MimeIterator to traverse the MIME tree structure to collect a list of attachments that you'd like to remove (and remove them). To do this, your code would look something like this:
var attachments = new List<MimePart> ();
var multiparts = new List<Multipart> ();
var iter = new MimeIterator (message);
// collect our list of attachments and their parent multiparts
while (iter.MoveNext ()) {
var multipart = iter.Parent as Multipart;
var part = iter.Current as MimePart;
if (multipart != null && part != null && part.IsAttachment) {
// keep track of each attachment's parent multipart
multiparts.Add (multipart);
attachments.Add (part);
}
}
// now remove each attachment from its parent multipart...
for (int i = 0; i < attachments.Count; i++)
multiparts[i].Remove (attachments[i]);
I created an application, that downloads emails and attachments as well using Mailkit.
I faced one problem: E-Mails sent from iOS with attached pictures were not processed correctly. MailKit did not add the images to the Attachments list.
I used this method to get only the text of the message:
private static string GetPlainTextFromMessageBody(MimeMessage message)
{
//content type needs to match text/plain otherwise i would store html into DB
var mimeParts = message.BodyParts.Where(bp => bp.IsAttachment == false && bp.ContentType.Matches("text", "plain"));
foreach (var mimePart in mimeParts)
{
if (mimePart.GetType() == typeof(TextPart))
{
var textPart = (TextPart)mimePart;
return textPart.Text;
}
}
return String.Empty;
}
This is the method I used to download only the .jpg files:
foreach (var attachment in message.BodyParts.Where(bp => !string.IsNullOrEmpty(bp.FileName)))
{
if (attachment.FileName.ToLowerInvariant().EndsWith(".jpg"))
{
//do something with the image here
}
}
I am using EWS to create a StreamingSubscription on an inbox. It is listening for the NewMail event. I am able to pull the From Address, Subject, Body, To Address, CC Address but not the BCC Address. Is there any way to see this list?
CODE:
static void OnEvent(object sender, NotificationEventArgs args)
{
String from = null;
String subject = null;
String body = null;
String to = null;
StreamingSubscription subscription = args.Subscription;
// Loop Through All Item-Related Events
foreach (NotificationEvent notification in args.Events)
{
ItemEvent item = (ItemEvent)notification;
PropertySet propertySet = new PropertySet(ItemSchema.UniqueBody);
propertySet.RequestedBodyType = BodyType.Text;
propertySet.BasePropertySet = BasePropertySet.FirstClassProperties;
// Parse Email
EmailMessage message = EmailMessage.Bind(service, item.ItemId, propertySet);
from = message.From.Address;
subject = message.Subject;
body = message.Body.Text;
if (message.ToRecipients.Count > 0)
{
to = message.ToRecipients[0].Address;
body += "\n TO FIELD";
}
else if (message.CcRecipients.Count > 0)
{
to = message.CcRecipients[0].Address;
body += "\n CC FIELD";
}
/************** Does not work! BccRecipients is always empty *****************/
else if (message.BccRecipients.Count > 0)
{
to = message.BccRecipients[0].Address;
body += "\n BCC FIELD";
}
/************* REST OF CODE ************************/
}
}
That would kind of defeat the point of a blind-carbon-copy. I dont believe it can be done.
Consider using the Journaling feature of Exchange. This uses something called "Envelope Journaling" which includes BCC information for messages within the Exchange environment.
For everything that comes from external sources (gmail) no BCC information is available.
This might help:
http://gsexdev.blogspot.com/2011/06/processing-bccs-in-exchange-transport.html
Hello I am developing an outlook Add-on, as part of the work flow it should take the mailItem body and subject, and for each recipient it should change the body of message according to recipient e-mail.
The problem is that it just sends the first e-mail and after Send(); it does not send the e-mail to other recipients
Outlook.Application application = Globals.ThisAddIn.Application;
Outlook.Inspector inspector = application.ActiveInspector();
Outlook.MailItem myMailItem = (Outlook.MailItem)inspector.CurrentItem;
myMailItem.Save();
if (myMailItem != null)
{
myMailItem.Save();
PorceesData(myMailItem);
}
..
..
..
..
private void ProcessData(MailItem oMailItem)
{
Recipients recipients = oMailItem.Recipients;
string Body = oMailItem.Body;
string To = oMailItem.To;
string CC = oMailItem.CC;
string bcc = oMailItem.BCC;
foreach (Recipient r in recipients)
{
if (r.Resolve() == true)
{
string msg = "Hello open the attached file (msg.html);
string address = r.Address;
oMailItem.Body = msg;
oMailItem.To = address;
oMailItem.Subject = "my subject"
foreach (Attachment t in oMailItem.Attachments)
{
t.Delete();
}
oMailItem.Attachments.Add(#"mydirectory");
oMailItem.Send();
}
_MailItem.Send() closes the current inspector. This isn't in the _MailItem.Send documentation, but is the actual Outlook implementation. You should probably come up with another approach. I'd suggest creating a new MailItem instance for each message you wish to send.
You can create a new MailItem using...
Outlook.MailItem eMail = (Outlook.MailItem)
Globals.ThisAddIn.Application.CreateItem(Outlook.OlItemType.olMailItem);
eMail.Subject = subject;
eMail.To = toEmail;
eMail.Body = body;
eMail.Importance = Outlook.OlImportance.olImportanceLow;
((Outlook._MailItem)eMail).Send();
After sending to all recipients you can manually close the current inspector using the following (Send() implicitly calls this method)
((Outlook._MailItem)myMailItem).Close(Outlook.OlInspectorClose.olDiscard)