Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MimeKit.MimeMessage]::new() throws an error when using standard library in Net Framework 4.8 #683

Closed
PrzemyslawKlys opened this issue Jun 12, 2021 · 35 comments
Labels
bug Something isn't working

Comments

@PrzemyslawKlys
Copy link

PrzemyslawKlys commented Jun 12, 2021

Describe the bug
I use your MimeKit/MailKit libraries in Mailozaurr PowerShell module. So far I've been using NET Standard libraries to support NET Core (PS 6, PS 7) and NET 4.5 library to support PowerShell 5.1. It worked but it was kind of double the amount of megs. So I tried to use NET STandard 2.0 in PowerShell 5.1 which should work just fine (because it's supported) but it throws an error whenever I try to use:

[MimeKit.MimeMessage]::new()

Error:

Exception calling ".ctor" with "0" argument(s): "The type initializer for 'MimeKit.ParserOptions' threw an exception."
At C:\Support\GitHub\Mailozaurr\Public\Send-EmailMessage.ps1:440 char:5
+     $Message = [MimeKit.MimeMessage]::new()
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : TypeInitializationException

Do you see any reason why would it throw an error like that? It works fine in PowerShell 6 and 7 so it would seem that MimeKit.ParserOptions could potentially have a code that only works in .NET Core but doesn't work in .NET 4.6.1+

image

I can of course use different libraries if NET Framework is used, but it;'s just unnecessary space filler.

Platform (please complete the following information):

  • OS: Windows 10
  • .NET Runtime:
  • .NET Framework: Net 4.6.2+ (I believe 4.8 or later is currently installed)
  • MimeKit Version: 2.13 but I checked 2.11, and 2.11 - same thing
@jstedfast
Copy link
Owner

ParserOptions is very simple, so I can't think of anything there that would cause problems.

Normally, when a similar exception has occurred for MimeMessage .ctor, it's been related to charset related and it's been a TypeLoadException (or some such) thrown in the CharsetUtils static .ctor

This is because not all character encodings (aka text encodings) are supported by default in .netstandard and it's necessary to pull in additional nugets for the non-unicode character encodings. Or at least that was the case with older .netstandard versions. I forget if that's an issue for 2.x.

Do you think it might be possible to get more information, such as line numbers or something?

I wonder if the ParserOptions error is just a side-effect of something else and is therefore a red-herring.

@PrzemyslawKlys
Copy link
Author

PrzemyslawKlys commented Jun 13, 2021

No, no line numbers. However:

 [MimeKit.ParserOptions]::new()

Gives:

Exception calling ".ctor" with "0" argument(s): "The type initializer for 'MimeKit.Utils.CharsetUtils' threw an exception."
At line:1 char:1
+ [MimeKit.ParserOptions]::new()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : TypeInitializationException

If I try to follow down

[MimeKit.Utils.CharsetUtils]

Error:

Unable to find type [MimeKit.Utils.CharsetUtils].
At line:1 char:1
+ [MimeKit.Utils.CharsetUtils]
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (MimeKit.Utils.CharsetUtils:TypeName) [], RuntimeException
    + FullyQualifiedErrorId : TypeNotFound

When I check what options I have in MimeKit.Utils - only 3 options are there

image

@jstedfast
Copy link
Owner

CharsetUtils is an internal class, it's not exposed in the public API.

I suspect this may be where things are breaking in CharsetUtils.cs?

#if NETSTANDARD
Encoding.RegisterProvider (CodePagesEncodingProvider.Instance);
#endif

@PrzemyslawKlys
Copy link
Author

I would say so. Any way this can be a workaround? Maybe I'm missing some NuGet?

@jstedfast
Copy link
Owner

I want to say it depends on the System.Text.Encoding.CodePages nuget package, but I'm not 100% positive.

@PrzemyslawKlys
Copy link
Author

I tried that, it didn't change anything :(

@jstedfast
Copy link
Owner

jstedfast commented Jun 15, 2021

I'm not sure what else you could try :(

Best I can offer is maybe try adding some logging to the CharsetUtils static .ctor to see if that helps narrow things down.

That class basically tries to load a bunch of widely-used text encodings and maps various aliases to them that are commonly used in mail headers. It tries to catch exceptions, but apparently some exceptions make it out.

https://github.com/jstedfast/MimeKit/blob/master/MimeKit/Utils/CharsetUtils.cs#L41

@PrzemyslawKlys
Copy link
Author

I guess I have no other way - I'll try to play with it and add some debugging/try/catches all over the place to find what is actually throwing this. Till then I will use 2 separate sets of libraries.

@jstedfast
Copy link
Owner

If you figure out where in the code an exception is being thrown, let me know and I will help you try to figure out a solution.

@jstedfast
Copy link
Owner

jstedfast commented Jun 23, 2021

Oh, I bet I know the issue...

I think that Register method was meant to be called from the main program and not a library as part of any initialization.

When that code runs in your .NET 4.8 environment, it throws because .NET 4.8 doesn't have that method - it's only supposed to be called from a .NET Core app.

@PrzemyslawKlys
Copy link
Author

Is there anything I can do?

@jstedfast
Copy link
Owner

No, I think the solution is for me to remove that line of code from MimeKit - if you want, can you test that theory for me?

If that works, then the next step is for me to write docs and a FAQ about needing to call that method from .NET Core apps manually (since MimeKit won't do it anymore).

Hopefully that won't break too many people, but I think if I'm right about this bug, then it'll be the Right Thing To Do(tm) since your use-case scenario should totally be expected to work.

@jstedfast jstedfast added the bug Something isn't working label Jun 23, 2021
@PrzemyslawKlys
Copy link
Author

Yes, lets try to remove that line and see how it goes. Maybe this could be somehow detected that it's running as part of Net Framework or Net Core?

@jstedfast
Copy link
Owner

jstedfast commented Jun 28, 2021

Did some more digging here...

It looks like the following code should work in .NET >= 4.6 according to the docs.

Encoding.RegisterProvider (CodePagesEncodingProvider.Instance);

Docs link: https://docs.microsoft.com/en-us/dotnet/api/system.text.encoding.registerprovider?view=netframework-4.6

Starting with .NET Framework 4.6, .NET Framework includes one encoding provider, CodePagesEncodingProvider, that makes the encodings available that are present in the full .NET Framework but are not available in the Universal Windows Platform. By default, the Universal Windows Platform only supports the Unicode encodings, ASCII, and code page 28591.

I re-read the comments above and I think I thought that this was being hit in .NET 4.8, but now that I just re-read again, it's .NET 4.5? Is that right? If so, then this is still likely the culprit.

@PrzemyslawKlys
Copy link
Author

The minimal version for Net Standard 2.0 is 4.6.1 and this is what I "support". I expect PowerShell 5.1 users to at least install 4.6.1 net framework but it should work for 4.8 as well.

I have 4.8 installed and it throws errors.

@jstedfast
Copy link
Owner

Ah, interesting...

jstedfast added a commit that referenced this issue Jul 28, 2021
@jstedfast
Copy link
Owner

This should be fixed in 2.14.0

@PrzemyslawKlys
Copy link
Author

Will test it out. Thank you ;)

@danielchent
Copy link

Hi
my development environment
windows 10, powershell 7, visual studio code / visual studio
i installed the module according to your instructions.
i copied the send email example that you have here
i keep getting the folowing error: " Unable to find type [MimeKit.MimeMessage] "
can you help?
thank you

@PrzemyslawKlys
Copy link
Author

You should take this into Mailozaurr repo and provide what exactly you're using, which version and when you get the error.

This is probably not proper way to report an issue.

jstedfast added a commit that referenced this issue Jul 5, 2022
Rely on developers calling this themselves.

Fixes issue #816
Fixes issue #792
Fixes issue #785
Fixes issue #683
@Chaos02
Copy link

Chaos02 commented Jan 18, 2023

Hi my development environment windows 10, powershell 7, visual studio code / visual studio i installed the module according to your instructions. i copied the send email example that you have here i keep getting the folowing error: " Unable to find type [MimeKit.MimeMessage] " can you help? thank you

Hi - This is probably caused by your Wrong Syntax.
It should be along the lines of:

$message = New-Object MimeKit.MimeMessage

You can type [MimeKit.MimeMessage]. into the powershell and hit tab to explore the object. Otherwise - loose the brackets!

@PrzemyslawKlys
Copy link
Author

Pretty sure the brackets work perfectly fine. New-Object is the old way (and slower) to work with types in PowerShell.

image

@Chaos02
Copy link

Chaos02 commented Jan 18, 2023

Regarding my issue:
This Issue still exists!
The Missing Latin1 support is one thing (I was able to solve by loading System.Text.Encoding from ASP.NET > V5)
However, there still persists another issue I cannot get solved:

When creating a new MimeMessage via New-Object MimeKit.MimeMessage I get the first-mentioned MimeKit.ParserOptions threw an exception.

Through the Automatic $Error variable (Which for some reason now is empty, even after a reboot) I recursively doug down in the .Innerexceptions property and ran a .ToString() on each of them, to get the exception message.
because of the weird $Error behaviour I will need to quote from memory as best as I can:

"System.Reflection.ConstructorInfo" in "System.Runtime" could not be loaded with a HResult of 0x80131515

I think this string is missing the System.Runtime assembly infos like Version and PublicKey but I had made sure before that they matched:
When viewing the AppDomain assemblies (via [System.AppDomain]::CurrentDomain.GetAssemblies() | Where-Object Location | Sort-Object -Property FullName | Select-Object -Property FullName, Location, GlobalAssemblyCache, IsFullyTrusted | Out-GridView)
I can see both MailKit/MimeKit DLLs loaded. Both are fully trusted.
I have also tried (additionally) loading the System.Reflection and System.Runtime DLLs from the ASP(?).NET 7 binary package. Both load with success but it doesn't help.

What I also made sure is that the Project I'm working on sits locally, to circumvent issues (TypeLoadExceptions) i got earlier.

At this point I've googled everything and doug deeply into it until my search results consistently only had about 2 entries.
Now I've desperately found this old thread which seems to be only half solved to me.

I've obtained MailKit.dll and MimeKit.dll v3.4.3.0 via the NuGet online repo and extracted the file for .NET 6 from the .nupkg archives.
I'm on Windows 11, developing a PowerShell (at this point more C#) (gui) application and have .NET SDK 7.0.102 and ASP.NET Core 7.0.2, aswell as Windows Desktop Runtime 7.0.2 installed to try solve this issue.

@PrzemyslawKlys
Copy link
Author

There's few more DLLs that are required for things to just work:

image

Default = 5.1, Core = PS7+

https://github.com/EvotecIT/Mailozaurr/tree/master/Lib you can see those files here. If you load them up it will work.

@Chaos02
Copy link

Chaos02 commented Jan 18, 2023

Is this for Mailozaurr only or just to use MailKit successfully?
Incase MailKit:
ouhh damn I totally didn't find this information in the nuGet dependencies or webpage..
Please make it more obvious for next time! ;)
Until then I'll test it out! Thank you!!

@PrzemyslawKlys
Copy link
Author

PrzemyslawKlys commented Jan 18, 2023

Mailozaurr works with Mailkit/MimeKit. DNSClient, EmailValidation, MicrosoftIdentity* and Google* are not needed, but the rest of it pretty much yes

@Chaos02
Copy link

Chaos02 commented Jan 18, 2023

Nope, still same results.
However I was now able to copy a full stacktrace: (Note end of first line!)

System.Management.Automation.MethodInvocationException: Ausnahme beim Aufrufen von ".ctor" mit 0 Argument(en):  "Der Typeninitialisierer für "MimeKit.ParserOptions" hat eine Ausnahme verursacht." ---> System.TypeInitializationException: Der Typeninitialisierer für "MimeKit.ParserOptions" hat eine Ausnahme verursacht. ---> System.TypeLoadException: Der Typ "System.Reflection.ConstructorInfo" in der Assembly "System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" konnte nicht geladen werden.
   bei MimeKit.ParserOptions..ctor()
   bei MimeKit.ParserOptions..cctor()
   --- Ende der internen Ausnahmestapelüberwachung ---
   bei MimeKit.MimeMessage..ctor()
   --- Ende der internen Ausnahmestapelüberwachung ---
   bei System.Management.Automation.DotNetAdapter.AuxiliaryConstructorInvoke(MethodInformation methodInformation, Object[] arguments, Object[] originalArguments)
   bei System.Management.Automation.DotNetAdapter.ConstructorInvokeDotNet(Type type, ConstructorInfo[] constructors, Object[] arguments)
   bei Microsoft.PowerShell.Commands.NewObjectCommand.CallConstructor(Type type, ConstructorInfo[] constructors, Object[] args)

Sorry for it being german ^^'
the HResult of the TypeLoadException is 0x80131501.
BTW same result when using [MimeKit.MimeMessage]::new()

@PrzemyslawKlys
Copy link
Author

Why dont you use Mailozaur?

@Chaos02
Copy link

Chaos02 commented Jan 18, 2023

Why dont you use Mailozaur?

II haven't looked enough into Mailozaur as a viable solution yet - My requirements are:

  • Fast API interface
  • Lightweight
  • adaptable

As far as I've looked, Mailozaurr is an incredibly complex solution and would probably run into the same error I have on my machine because it also uses [MimeKit.MimeMessage]::new()
The only difference to my approach is that it uses Add-Type instead of [System.Reflection.Assembly]::LoadFrom(string path)

Edit: I need to send emails. My GUIForm offers an RTF textbox, which I want to simply pass to MailKit. MailKit does support an RTF body, Mailozaurr does not.

@PrzemyslawKlys
Copy link
Author

well have you tried installing Mailozaurr and seeing if you have that error? If not - you can just use "native" mailkit/mimekit with it as well. Just because the functions simplify things you don't want doesn't mean you have to use them.

@jstedfast
Copy link
Owner

The dll that has been the cause of most of the reported TypeLoadExceptions over the past 6+ months has been System.Runtime.CompilerServices.Unsafe. MimeKit no longer event attempts to load System.Text.Encoding.CodePages anymore for similar reasons.

Apparently there is/was a bug in the standard MSBuild targets that incorrectly resolved which version of that dll to bundle in the app directory if multiple nugets depended on different versions and also incorrectly populated the assembly mappings.

Essentially, there seems to be no way for me to solve the issue without dropping the dependency completely.

@PrzemyslawKlys
Copy link
Author

PowerShell, especially PowerShell 5.1 adds it's own problems with DLLs. In some cases you need to resolve to binary workaround such as

https://github.com/EvotecIT/ImagePlayground/blob/ca2b14a24d182869be1e7654edaa779f72838aa9/Sources/ImagePlayground.PowerShell/OnImportAndRemove.cs#L1-L45

Othrewise I wasn't able to get it even up and running. But so far for Mailozaurr and your libraries I don't have problems anymore. I believe the problem is picking correct DLL version that works with what you are using, or build empty Visual Studio project that just is there to get you proper dependencies in place.

@jstedfast
Copy link
Owner

@PrzemyslawKlys Yea, I think in all of the cases so far where someone is getting a TypeLoadException with MimeKit now (typically the Unsafe.dll), it is usually because their project is also depending on another nuget which depends on a different version of the Unsafe.dll.

With that in mind, I had bumped the Unsafe.dll dependency to 6.0.0 instead of using an old version, this way it would be easier to make everything work. Now users just need to edit their own app.config and create the mapping (or let VS do it).

@Chaos02
Copy link

Chaos02 commented Jan 19, 2023

@PrzemyslawKlys I have tested Mailozaurr and it does (for some magical reason) not have any issues with MimeKit::new()...
However it lacks the RTF support - Shall I open a Ticket?
It would also be great if I could send batches of mails from the same account with some shared attachments but an individual one per mail (I already had built the logic for this but since MimeKit troubles me...)
If it takes even one second per mail that is too long.

Edit: I had mismatched DLLs... sorry to bother!

@PrzemyslawKlys
Copy link
Author

You could always add RTF support to mailozaurr - make a PR - it's 5 lines of code. It already supports attachments and has all the logic so it's as easy as adding small feature.

If the server is fast it send an email in 250ms or so

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants