Help Sending Email (MailMessage Deserialize Problem)

Hi everyone,

I need your help. I’m trying to get my app to send emails in the background using Hangfire. We have an email helper class our company created so I’m not using Postal. That helper class works just fine without Hangfire, but it runs synchronously and slows everything down. I’m running into a problem with the DeserializeArguments method when the email is passed to it. I’m using BackgroundJob.Enqueue( () => SendEmail(message)); [where message is an instance of MailMessage] and get this in the dashboard:

Failed: An exception occurred during arguments deserialization.
System.NotSupportedException

TypeConverter cannot convert from System.String.

System.NotSupportedException: TypeConverter cannot convert from System.String.
at System.ComponentModel.TypeConverter.GetConvertFromException(Object value)
at System.ComponentModel.TypeConverter.ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, Object value)
at System.ComponentModel.TypeConverter.ConvertFromInvariantString(String text)
at Hangfire.Common.Job.DeserializeArguments(IJobCancellationToken cancellationToken)

It doesn’t seem to matter whether I use the Enqueue method on the SendEmail method that our company created or the actual SendMailAsync method the helper calls - the deserialization fails each time. I could also change the methods to no longer be Async, but I doubt that’s related. It seems like Hangfire is having a problem converting that MailMessage object.

Any ideas? Let me know if I need to provide more information.

Thanks!

I’m guessing you can’t, MailMessage isn’t Serializable, probably has code that corresponds to things in real life, like network sockets. Bad programming on MS’s part, because 90% of a mail message should be plain text & obviously very serializable.

1 Like

Yep, I figured out that was the issue. I just made a separate regular object and changed the SendMail method to accept that object and turn it into a MailMessage. That way I could just pass Hangfire my own object and it could de-serialize it with no problems.

I’ve had nothing but good experience wrapping all MailMessage-related objects in my own classes which then in turn are Serializable. You can see my implementation here https://bitbucket.org/burningice/compositec1contrib.email/src/0bba07df532c8134717cfb40757f4cb22f002b1d/Email/Serialization/?at=default

You can even get a EML representation of your MailMessage just by using .Net (thats a one-way conversion though) https://bitbucket.org/burningice/compositec1contrib.email/src/0bba07df532c8134717cfb40757f4cb22f002b1d/Email/MailMessageSerializeFacade.cs?at=default#cl-78

Hi burningice, how do we actually use your code?
I cloned your repo and when I tried nothing gets serialized… bear in mind I am using sql server where everything is serialized into json, what I got was only an empty json string ["{}"],

Then I realized this is because everything is private in your SerializeableMailMessage class, so I change everything into public properties.

For example…

//I changed this...
//private readonly string _body;
//into this...        
public string Body { get; set; }

Then it gets serialized into json ‘properly’, however upon deserialization I still get TypeConverter cannot convert from System.String error…

I finally gave up and wrote a simple code like so… (it is obviously does not support everything MailMessage has but it is adequate for my needs at the moment).

[Serializable]
public class SimpleMailMessage
{
	public string From { get; set; }
	public string DisplayName { get; set; }
	public string To { get; set; }
	public string ReplyTo { get; set; }
	public string Subject { get; set; }
	public string Body { get; set; }

	public MailMessage ToMailMessage()
	{
		return new MailMessage
		{
			Body = Body,
			From = new MailAddress(From, DisplayName),
			IsBodyHtml = true,
			Subject = Subject,
			To = { To },				
			ReplyToList = { ReplyTo }
		};
	}
}

@Rosdi Its important to note, that just because a class i marked as Serializable, doesn’t mean that you can convert it to JSON. JSON only support so and so many datatypes and is not able to represent all .net types.

That a class is Serializable means, that .net is able to “dump” the content of the class-instance and recreate the instance again from that “dump”. The easiest is to represent the dump is a binary file, which can then be saved in a text-file using Base64 encoding.

That is basically whats going on here

1. Serialize a MailMessage to a binary file on disk

2. Serialize a MailMessage to a Base64 encoded text string (ie. for saving a property in a JSON document)