Hide/show the buttion BEFORE you start the next process/thread.
eg:
btn.enabled = false;
new Thread (() =>
{
// thread work start here;
//emailing
}.start();
That way, the button is disabled, process starts, as always then a whole new fresh copy of the web page is then sent back to the client side.
If you need to update that page? Then you have really only 2 practial choices.
You can start a timer on the page - call a ajax routine, and it will have to check say some session() value that the process sets = "done".
The other way would be to introduce signalR into your applcation.
https://learn.microsoft.com/en-us/aspnet/signalr/overview/getting-started/introduction-to-signalr#:~:text=What%20is%20SignalR%3F%20ASP.NET%20SignalR%20is%20a%20library,process%20of%20adding%20real-time%20web%20functionality%20to%20applications.
I have a number of processing routines. I start the process, and the I start a timeer on the page. It re-freshens a update panel every 1 second until such time the session("MyProcessDone") = true, and then I stop the timer at that point (and of course update the spinner/animated gif). So, you can start a timer on the web page - and check some session() value, or as noted, introduce signalR into your applicaton.