Modify SmtpSection in web.config in c# code in asp.net? - c#

I have set up the following in my web.config to have multiple smtp settings defined:
<sectionGroup name="mailSettings">
<section name="smtp_1" type="System.Net.Configuration.SmtpSection" requirePermission="false"/>
<section name="smtp_2" type="System.Net.Configuration.SmtpSection" requirePermission="false"/>
</sectionGroup>
</configSections>
<mailSettings>
<smtp_1 deliveryMethod="Network" from="xxx#hotmail.com">
<network host="smtp.live.com" port="587" userName="xxx#hotmail.com" password="xxx" defaultCredentials="false"/>
</smtp_1>
<smtp_2 deliveryMethod="Network" from="yyy#gmail.com">
<network host="smtp.gmail.com" port="465" userName="yyy#gmail.com" password="yyy" defaultCredentials="false"/>
</smtp_2>
</mailSettings>
I have been able to retrieve any of the settings using code and I have set up a function to iterate through the config file and pull out each smtp setting and add to a dropdownlist.
The only thing that doesn't want to work is actually writing back to the web.config (either adding a new smtp or modifying an existing one). I have used the following C# code:
Configuration webConfig = WebConfigurationManager.OpenWebConfiguration("~");
SmtpSection smtpSection = (SmtpSection)ConfigurationManager.GetSection("mailSettings/smtp_1");
smtpSection.From = "zzz#hotmail.com";
smtpSection.Network.Port = 25;
smtpSection.Network.UserName = "xxx";
smtpSection.Network.Password = "xxx";
webConfig.Save();
But this returns the error:
The configuration is read only.
This code works perfectly fine, but of course it modifies the primary smtp settings in the system.net (where you cannot have multiple smtp settings).
System.Net.Configuration.MailSettingsSectionGroup mailSection = webConfig.GetSectionGroup("system.net/mailSettings") as System.Net.Configuration.MailSettingsSectionGroup;
mailSection.Smtp.From = "xxx#hotmail.com";
mailSection.Smtp.Network.Host = "smtp.live.com";
mailSection.Smtp.Network.Port = 25;
webConfig.Save();
Been racking my brain over this and can't seem to find the answer. Feels like it's going to be something so simple (or just not possible). If not, will probably need to encrypt settings and store in the DB.
Thanks! :)

Related

SMTP Authentication Exception after power outage

Exception type: AuthenticationException
Exception message: The remote certificate is invalid according to the validation procedure.
I use google's SMTP server to send email messages from an ASP.Net application. The code below has been used to successfully send messages for over a year until yesterday, which correlates to the server going down due to a power outage.
Here is the code I am using.
c#
public static MailMessage CreateMailMessage(List<string> destination, string subject, string body)
{
MailMessage m = new MailMessage();
foreach (string email in destination)
{
m.To.Add(email);
}
m.From = new MailAddress(from);
m.Subject = subject;
m.Body = body;
m.IsBodyHtml = true;
return m;
}
public static void SendMailMessage(MailMessage mailMessage)
{
SmtpClient smtpClient = new SmtpClient();
smtpClient.Send(mailMessage);
}
web.config
<configuration>
<configSections>
<section name="resizer" type="ImageResizer.ResizerSection" requirePermission="false" />
</configSections>
<connectionStrings configSource="ConnectionStrings.config" />
<system.net>
<mailSettings>
<smtp configSource="SmtpSettings.config" />
</mailSettings>
</system.net>
<configuration>
SmtpSettings.config
<smtp deliveryMethod="Network">
<network host="smtp.gmail.com" port="587" enableSsl="true" userName="username" password="password"/>
</smtp>
I have tested the code on another server, and it works as expected. Could there be some service that hasn't started on the server?
The problem has something to do with SSL certificate validation. It's possible that your X.509 certificate database got corrupted or one of the certificates in the chain (for validating Google's certificate) is no longer trusted for some reason. It might even be a problem with Google's SSL certificate.
Sadly my answer is probably not super helpful, but it's all I can think of.

"The SMTP host was not specified." - but it is specified?

I'm slightly baffled here - I'm receiving the following error:
The SMTP host was not specified.
Even though my code appears to be correct (from what I can see).
I am able to do it manually by including all the details inside of the controller, e.g.
SmtpClient smtpClient = new SmtpClient("smtp.gmail.com");
smtpClient.Port = 587;
... etc
But I shouldn't have to do this, as I want to use the details inside mailSettings (Making it re-usable for various different controllers).
mailSettings in my Web.Config file:
<system.net>
<mailSettings>
<smtp from="example#gmail.com" deliveryMethod="Network" >
<network host="smtp.gmail.com" defaultCredentials="true"
port="587" enableSsl="true" userName="example#gmail.com"
password="example"/>
</smtp>
</mailSettings>
</system.net>
My Controller action:
[HttpPost]
public ActionResult SubmitFeature(FormData formData)
{
SmtpClient smtpClient = new SmtpClient();
MailMessage mail = new MailMessage();
mail.To.Add(new MailAddress("example#gmail.com"));
mail.Body = "Test";
smtpClient.Send(mail);
return View("Example");
}
Is there anything I'm missing which may be causing this? I haven't messed around with any other settings in Web.Config, they are as is when setting up a new MVC5 project.
In a clean MVC project, I am unable to replicate your issue. Following the ScottGu blog post here, I was able to get a gmail sent email without issue (VS 2013, .NET 4.5.1, MVC 5). Note the the <system.net> element is a top level element and not nested inside of AppSettings or <system.web>.
Important
There are a few web.config files in your solution, ensure that the mailSettings is inserted into the root level web.config (and not the one located in the Views folder)
Web.Config
<configuration>
<system.net>
<mailSettings>
<smtp from="myEmail#gmail.com">
<network host="smtp.gmail.com"
port="587"
enableSsl="true"
userName="myEmail#gmail.com"
password="SuperSecretPwd"
defaultCredentials="false" /> <!--This must be false on Gmail-->
</smtp>
</mailSettings>
</system.net>
</configuration>
Controller
var smtpClient = new SmtpClient();
var msg = new MailMessage();
msg.To.Add("MyOtherAddress#yahoo.com");
msg.Subject = "Test";
msg.Body = "This is just a test email";
smtpClient.Send(msg);
It is unclear if some of the extra attributes you have included are causing issues (thought they shouldn't) such as delivery method. Also, is there a setting for allowing SMTP access or is that just for IMAP/POP delivery?
If you can test and are successful in a clean project, then this would point to either a web.config transformation problem or some other setting(s) in your project overriding the web.config settings that you have in place.
The solution was mentioned in the Chat, but never edited into the answer above.
Make sure that you make these settings in the web.config of the Root Level and not in the Views folder.
#Tommy: ...this looks like the web.config from your Views folder and not the web.config at the root of the application
If your code is right so,Turn on "Less secure app access" in your Gamil email account

how to handle proxy properly in .NET

I have an Excel AddIn written in C#, which connects to server to get data via httpwebrequest
One client has proxy settings "Use Automatic Configuration Script" checked and it uses some script there.
My addin is not able to connect to server in this case.
So I open fiddler to check why it fails. Then my addin starts working.
I checked proxy settings with fiddler open, look, it is changed to "Use a proxy server for your LAN"
I want to do the same thing in my code, use the proxy setting from IE settings and use it in my code.
Do you know how to accomplish this?
What I have now is as below and does NOT work. Thanks
private static void SetProxyIfNeeded(HttpWebRequest request, Uri uri)
{
var stopWatch = new Stopwatch();
stopWatch.Start();
if (_proxy == null)
{
_proxyUri = WebRequest.GetSystemWebProxy().GetProxy(uri);
_proxy = new WebProxy(_proxyUri, true)
{
Credentials = CredentialCache.DefaultNetworkCredentials
};
if (_proxyUri != null && !string.IsNullOrEmpty(_proxyUri.AbsoluteUri) && !_proxy.Address.Equals(uri) && !IsLocalHost(_proxy))
{
_realProxy = true;
}
else
{
_realProxy = false;
}
}
//if there is no proxy, proxy will return the same uri
//do we need check if client.Proxy is null or not,
if (_realProxy)
{
request.Proxy = _proxy;
}
stopWatch.Stop();
Helper.LogError("\r\n Got proxy in " + stopWatch.ElapsedMilliseconds + "ms.\r\n");
}
In addition, I have a config file
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="System.Configuration.IgnoreSectionHandler" />
</configSections>
<appSettings>
<add key="log4net.Config" value="log4netConfig.xml" />
</appSettings>
<system.net>
<defaultProxy enabled ="true" useDefaultCredentials = "true">
<proxy usesystemdefault ="True" bypassonlocal="True"/>
</defaultProxy>
</system.net>
</configuration>
Edit:
client updates from their IT guy, looks like pac is downloaded but it is not used
I do not know why it is not used, I specify to use it in each request except cometd which has no way to specify proxy, maybe that's the issue?
If using an app.config for your AddIn is an option (I know this is tricky with Office Addins) you could handle all the proxy configuration there:
<configuration>
<system.net>
<defaultProxy>
<proxy
usesystemdefault="true"
bypassonlocal="true"
/>
</defaultProxy>
</system.net>
</configuration>
See <defaultProxy> Element (Network Settings) on MSDN for details.

Email Configuration Settings not being fetched

I have application that fetches email configuration settings such as host (SMTP Server name), username (SMTP Username) and Password from App.Config File as shown below
<system.net>
<mailSettings>
<smtp from="name#example.com"><network host="smtp.gmail.com" userName="test123#gmail.com" port="25" password="PassworD"/>
</smtp>
</mailSettings>
</system.net>
Now i wish to configure the settings that i have set in database and NOT from App.Config File. From database the credentials are not available in SMTPClient's properties .FYI, they are saved in database as well as the values are also correct.
Please Help!
Thanks
When you instantiate the SMTPClient just set the values specifically there. This overrides the settings from your app.config/web.config file.
var msg = new System.Net.Mail.MailMessage("from#yoursite.com", "to#somesite.com", "Subject", "Body text...");
var c = new System.Net.Mail.SmtpClient("smtp.gmail.com", 25);
c.Credentials = new System.Net.NetworkCredential("test123#gmail.com", "PassworD");
c.Send(msg);
when you were using the web.config version the settings were automatically filled in for you. Now as you have saved it in DB, you need to specify the settings.

How can I save an email instead of sending when using SmtpClient?

I am using SmtpClient to send an email with an attachment.
However for a certain batch we need to somehow save the MailMessage instead of sending them.
We are then thinking/hoping to manually upload the messages to the users drafts folder.
Is it possible to save these messages with the attachment intact (impossible, I would have thought). Or alternatively upload the messages to a folder in the users account?
If anyone has any experience of this, I'd much appreciate a bit of help or a pointer.
When testing in ASP.NET we save our emails to a folder rather then send them through an email server. Maybe you could change yourweb.config settings like this for your batch?
<system.net>
<mailSettings>
<smtp deliveryMethod="SpecifiedPickupDirectory">
<specifiedPickupDirectory pickupDirectoryLocation="c:\Temp\mail\"/>
</smtp>
</mailSettings>
</system.net>
Additional Info:
MSDN: <specifiedPickupDirectory> Element (Network Settings)
Configuring SmtpClient to drop emails in a folder on disk
As well as the SpecifiedPickupDirectory information of the other answers, if you want to ensure your emails are sent to a folder relative to the site root - handy in testing on build servers where you don't know the paths - you can add a quick check in your email sending code:
SmtpClient client = new SmtpClient();
...
// Add "~" support for pickupdirectories.
if (client.DeliveryMethod == SmtpDeliveryMethod.SpecifiedPickupDirectory && client.PickupDirectoryLocation.StartsWith("~"))
{
string root = AppDomain.CurrentDomain.BaseDirectory;
string pickupRoot = client.PickupDirectoryLocation.Replace("~/", root);
pickupRoot = pickupRoot.Replace("/",#"\");
client.PickupDirectoryLocation = pickupRoot;
}
And your tests will look something like this (make sure you use App_Data so IIS can write to the folder):
// Arrange - get SitePath from AppDomain.Current.BaseDirectory + ..\
string pickupPath = Path.Combine(SitePath, "App_Data", "TempSmtp");
if (!Directory.Exists(pickupPath))
Directory.CreateDirectory(pickupPath);
foreach (string file in Directory.GetFiles(pickupPath, "*.eml"))
{
File.Delete(file);
}
// Act (send some emails)
// Assert
Assert.That(Directory.GetFiles(pickupPath, "*.eml").Count(), Is.EqualTo(1));
This can help - Adding Save() functionality to Microsoft.Net.Mail.MailMessage
The main ideia, make an extension to MailMessage ,that by reflection making a save method.
You can configure this with the system.net setting in your web.config / app.config file.
<system.net>
<mailSettings>
<smtp deliveryMethod="Network">
<network host="mail.mydomain.com" port="25" />
</smtp>
<!-- Use this setting for development
<smtp deliveryMethod="SpecifiedPickupDirectory">
<specifiedPickupDirectory pickupDirectoryLocation="C:\Temp" />
</smtp>
-->
</mailSettings>
</system.net>
Also, here's a link with info on migrating from System.Web.Mail to System.Net.Mail.
A bug also requires adding as a workaround in some versions of the framework. So the completed version looks like:
<system.net>
<mailSettings>
<smtp deliveryMethod="SpecifiedPickupDirectory">
<specifiedPickupDirectory pickupDirectoryLocation="c:\Temp\mail\"/>
<network host="localhost" />
</smtp>
</mailSettings>
</system.net>

Categories

Resources