Let me recap this first: a static class cannot have instances so you use its methods with the class's name and a singleton class can only have 1 instance to be shared by others.
for a static class, you need to include that in your code file. for a singleton class, you will first create an instance then pass it to other methods in their parameter list.
In the context of aspnet, since we will have only 1 instance, we leave its creation and disposal to the framework with services.AddSingleton<ISingleton, Singleton>();
and get it to our controller by public SomeController(ISingleton singleton)
. when visitors hit this controller endpoint, all of their requests will be different but then handled by this single instance. aspnet will determine which singletons your controller needs, by their interfaces, and inject only those requested.
whether be a server-side global state holder, a database connector, or an email-sender in your case, all activity you implement will go through this singleton instance. you can implement a load balancer into it so requests can be processed without bottlenecks.
on the other hand, for a static class, you will prefer short-lived methods as they will run separately for every request to the controller. distance converter is one such method. it won't require any long processes to do its job, nor it will depend on other expensive resources. however, you may want to cache most frequent calculations and send responses from the cache, then converting this distance converter into a singleton that uses resources for long times would be a better idea.
so in short, depending on the use of resources, you will prefer either short-lived independent methods or long-lived methods with lots of expensive operations.
seeing OP has a confusion about SMTPClient
he uses, I wanted to add a few more lines.
you need to ask a question: does this client opens a channel to SMTP server and holds it for long time uses, or it just sends 1 message over it and needs be closed after.
some clients have one-time use core functionality, others build upon this core behavior and add a pool of pre-open single-use connections. the core functional class can be used both as a static, given resources as parameters, or be a singleton if it allows having initialized resources other than the connection itself. both cases will need to open a channel to SMTP server only when they are used, and that will cause delays. lastly, if it has to be closed after use, then the core functionality cannot be used as a singleton, as we need the alive throughout the life of our service.
on the other hand, if the client uses a pool of connections, there is no argue that it will be a singleton and positively affect the user experience. a side note here will be implementing one's own class having this pool of connections if no other current library is available in project's use environment.