smtp connection works in telnet but not in ASP -- same server, same credentials - asp.net

I'm trying to send email from an ASP.NET using my SendGrid account. It works on my dev machine, but not in production, even though the credentials are the same. Likewise, in production I can connect to the SMTP server via telnet (using base64 encoded credentials), but the ASP site can't connect--I get error "Unauthenticated senders not allowed."
I've tried a mix of port numbers (25, 587, 465 -- my site is SSL). Using port 465 times out. 25 and 587 return respond immediately--but with the login error. This is really baffling because, like I say, it's the same credentials on dev machine and production.
I looked very briefly at Microsoft Network Monitor 3.4, but could not make heads or tails of it. I was hoping it would tell me the blow-by-blow commands being sent since I suspect the web site is doing something a little different from how telnet connects, but I don't know what.
Note I also asked my web host if outgoing traffic on these ports were blocked on production firewall, but they aren't.
Here's the actual code--like I say works fine on localhost, but SMTP connection fails in production
[AllowAnonymous]
[HttpPost]
public ActionResult ResetPasswordSend(string email)
{
List<string> userList = new List<string>();
try
{
string[] invalidChars = new string[] { ";", "," };
foreach (var invalidChar in invalidChars) if (email.Contains(invalidChar)) throw new Exception("Email contains invalid character.");
int count = 0;
// since emails are not unique, I must launch resets for all of them
var users = _db.HsProfile.Query("[Email]=#0", SqlDb.Params(email));
foreach (var profile in users)
{
count++;
userList.Add(profile.UserName);
var token = WebSecurity.GeneratePasswordResetToken(profile.UserName, 15);
WebMail.Send(profile.Email, "HumaneSolution.com Password Reset for user " + profile.UserName,
"You received this email because you or someone with your email address requested a password reset on HumaneSolution.com. " +
"If you didn't do this, then you don't need to take any action, and nothing will happen.\n\n" +
"To proceed with the password reset, click the link below within 15 minutes:\n\n" +
Url.BaseUrl("Account/EnterNewPassword/" + token) + "\n\n" +
"Sent to: " + email + " at " + DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToLongTimeString() + "\n" +
"User name: " + profile.UserName);
}
if (count == 0) throw new Exception("Email " + email + " is not registered at HumaneSolution.com.");
}
catch (Exception exc)
{
ViewBag.Error = exc.Message;
}
return View(userList);
}

Based on suggestion from SendGrid, I re-wrote the email code so it does not use WebMail.Send but rather the SmtpClient and MailMessage objects explicitly. SendGrid says there might be some kind of timing problem in how ASP.NET loads credentials from the config file automatically. Here's exactly what they said:
Are you by chance storing your SendGrid credentials in a configuration file, separate from the code that connects to our SMTP server? The reason I ask is because I have seen rails and C# configurations like this receive the unauthenticated error due to the credentials not being passed at the correct time. Usually this is solved by moving the credentials directly in with the code instead of a separate configuration file. Give that a try and see if you notice a difference.<<
I didn't follow their advice completely -- i.e. I'm still using config file, but I'm loading the config values in subclasses of SmtpClient and MailMessage so I avoid hardcoding creds in my app. Anyway, it worked, all is well again.

Related

Sending a mail or invite through asp

I'm trying to send email or invite dynamically using asp page.
I used,
Oapp = new Outlook.Application();
But the problem is when executed, the page tries to open a new outlook application and sends a mail. I want the page to use the existing or open outlook application and send a mail.
Can anyone help me???
Microsoft does not currently recommend, and does not support, Automation of Microsoft Office applications from any unattended, non-interactive client application or component (including ASP, ASP.NET, DCOM, and NT Services), because Office may exhibit unstable behavior and/or deadlock when Office is run in this environment.
If you are building a solution that runs in a server-side context, you should try to use components that have been made safe for unattended execution. Or, you should try to find alternatives that allow at least part of the code to run client-side. If you use an Office application from a server-side solution, the application will lack many of the necessary capabilities to run successfully. Additionally, you will be taking risks with the stability of your overall solution. Read more about that in the Considerations for server-side Automation of Office article.
As a workaround you may consider using EWS or Outlook API, see EWS Managed API, EWS, and web services in Exchange for more information.
For sending emails use System.Net.* classes for sending emails from the server-side.
public static void CreateMessageWithAttachment(string server)
{
// Specify the file to be attached and sent.
// This example assumes that a file named Data.xls exists in the
// current working directory.
string file = "data.xls";
// Create a message and set up the recipients.
MailMessage message = new MailMessage(
"jane#contoso.com",
"ben#contoso.com",
"Quarterly data report.",
"See the attached spreadsheet.");
// Create the file attachment for this e-mail message.
Attachment data = new Attachment(file, MediaTypeNames.Application.Octet);
// Add time stamp information for the file.
ContentDisposition disposition = data.ContentDisposition;
disposition.CreationDate = System.IO.File.GetCreationTime(file);
disposition.ModificationDate = System.IO.File.GetLastWriteTime(file);
disposition.ReadDate = System.IO.File.GetLastAccessTime(file);
// Add the file attachment to this e-mail message.
message.Attachments.Add(data);
//Send the message.
SmtpClient client = new SmtpClient(server);
// Add credentials if the SMTP server requires them.
client.Credentials = CredentialCache.DefaultNetworkCredentials;
try
{
client.Send(message);
}
catch (Exception ex)
{
Console.WriteLine("Exception caught in CreateMessageWithAttachment(): {0}", ex.ToString() );
}
// Display the values in the ContentDisposition for the attachment.
ContentDisposition cd = data.ContentDisposition;
Console.WriteLine("Content disposition");
Console.WriteLine(cd.ToString());
Console.WriteLine("File {0}", cd.FileName);
Console.WriteLine("Size {0}", cd.Size);
Console.WriteLine("Creation {0}", cd.CreationDate);
Console.WriteLine("Modification {0}", cd.ModificationDate);
Console.WriteLine("Read {0}", cd.ReadDate);
Console.WriteLine("Inline {0}", cd.Inline);
Console.WriteLine("Parameters: {0}", cd.Parameters.Count);
foreach (DictionaryEntry d in cd.Parameters)
{
Console.WriteLine("{0} = {1}", d.Key, d.Value);
}
data.Dispose();
}

How Can I Specify Credentials for Simple Authentication in SSIS SMTP Connection Manager?

We have several asp.net web apps that send emails, and the MailMessage object is configured with an SMTP server, username and password. The emails are sent with no problems.
In an SSIS package, I added an SMTP connection manager, and I configured the smtp server. I set UseWindowsAuthentication=True because I don't see where I type in username/password.
When I run the package from SQL Server Agent, the SSIS sends the email correctly, so apparently, the user/password is not needed.
So how can the SMTP package send an email without the user credentials? Does it make sense that the asp.net don't need the credentials either?
We're all under the same company network and we use Exchange Server.
Thanks.
Create a SMTP Connection Manager with a parameterized ConnectionString property with a string which contains the smtp user and password.
Create connection using New Connection... option selecting SMTP as type.
Save without any connection settings. Give it any name you want.
Right click the connection and select Parameterize...
Select Property = ConnectionString
Select Create new parameter (e.g. SMTPConnectionManager_ConnectionString)
Set Value to connection string (e.g. SmtpServer=aspmx.l.google.com; port=25; UseWindowsAuthentication=False;EnableSsl=False; user=user#gmail.com; password=password123)
Set scope at appropriate level for your deployment method (Package or Project).
Click OK
Check out this link.
It explains that the package is using the Sql Server Agent account to connect to the host.
Furthermore, the SMTP connection manager supports only anonymous authentication and Windows Authentication. It does not support basic authentication - as stated in the documentation.
The answer from Alan Gaylor didn't work for me, but doing the following in a script task, not an email task, worked:
using System.Diagnostics;
using System.Net;
using System.Net.Mail;
public void Main()
{
string UserName = Dts.Variables["UserName"].Value.ToString();
string Password = Dts.Variables["Password"].Value.ToString();
string EmailRecipient = Dts.Variables["EmailRecipient"].Value.ToString();
string EmailSender = Dts.Variables["EmailSender"].Value.ToString();
string SMTPEndPoint = Dts.Variables["SMTPEndPoint"].Value.ToString();
Int32.TryParse(Dts.Variables["SMTPPort"].Value.ToString(), out int SMTPPort);
string MessageSubject = Dts.Variables["MessageSubject"].Value.ToString();
string MessageBody = Dts.Variables["MessageBody"].Value.ToString();
MailMessage msg = new MailMessage();
msg.To.Add(new MailAddress(EmailRecipient));
msg.From = new MailAddress(EmailSender);
msg.Subject = MessageSubject;
msg.Body = MessageBody +
"\n" +
"\n" +
"DISCLAIMER: The information contained in this transmission may contain privileged and confidential information. " +
"It is intended only for the use of the person(s) named above.If you are not the intended recipient, " +
"you are hereby notified that any review, dissemination, distribution or duplication of this communication " +
"is strictly prohibited. If you are not the intended recipient, please contact the sender by reply email and destroy all copies of the original message.";
SmtpClient client = new SmtpClient(SMTPEndPoint, SMTPPort)
{
EnableSsl = true,
DeliveryMethod = SmtpDeliveryMethod.Network,
Credentials = new NetworkCredential(UserName, Password)
};
try
{
client.Send(msg);
}
catch (Exception e)
{
Debug.WriteLine(e);
}
Dts.TaskResult = (int)ScriptResults.Success;
}
Follow Below steps
Create a Send Mail Task, then create a new smtpConnection.
Type your Mail server name and click OK
Right-click on the SMTP Connection Manager and click Parameterize.
Select ConnectionString from the property list
Add username, password and port to your connection string value
SmtpServer=mail.yourServerName.com;UseWindowsAuthentication=False;EnableSsl=False;port=portnumber;user=YourUserName;Password=YourPassword;

Communicating a GPS/GPRS/GSM tracker with the server

I am developing a vehicle tracking system which uses GPS/GPRS/GSM. The tracking device I am currently using is GV100, a GPS/GPRS/GSM tracker from Quectel ([www.quectel.com][1].)
I am not able to establish connection between the device and the backend server. My question particularly is:
How do I send commands (AT Commands) to the device from the server?
How do I accept the response (reports and acknowledgement messages) from the device to save it in the database?
I sent command to the device with the MGV100 Manage Tool (Software provided by Quectel) via serial port. And I got acknowledgement SMS message on GSM enabled mobile telephone. Now, I want to send message from the server and accept reply on the server (not by SMS). I don’t know how to send command and receive the reply. I have no previous experience in developing such systems.
It would be great if I can get a sample code and setup procedures if it requires.
Where can I get a relevant tutorial for the case I mentioned?
Thanks jhonkola
To understand how server receives and send data to the device, I decided to first implement the communication between the client (currently my PC) and server. Though my ultimate goal is communicating with the device, currently I am trying to establish connection from my PC to the server. If I succeed in this, I will strive to communicate to server from the device which needs IP address and port number of server to send and receive data.
This is my assumption how to do it:
I can open a port on the server from .cs code so as to communicate
using TCP/UDP.
Client then can send and receive data via this
port.
I can save the data sent from the client on server's file
system and review it any time. (Am not storing the data in relational database because I don't want to bother about database issues now.)
This is how I tried to implement:
Server a C# Web Application:
When a button is clicked it opens a port and listens to client
protected void btnConnect_Click(object sender, EventArgs e)
{
try
{
continueListening = true;
while (continueListening)
{
int port=Int32.Parse(txtPort.Text);
lblOutput.Text = "Port is now " + port +". Waiting for connection";
TcpListener myList = new TcpListener(IPAddress.Parse(txtIpAddress.Text), port);
myList.Start();
Socket s = myList.AcceptSocket();
lblOutput.Text="Connection accepted from " + s.RemoteEndPoint;
byte[] b = new byte[100];
int k = s.Receive(b);
lblOutput.Text = ("Recieved...");
String obtainedText = "";
for (int i = 0; i < k; i++)
{
obtainedText = obtainedText + " " + (Convert.ToChar(b[i]));
}
writeToTextFile("C:/Users/MekAtIbex/Desktop/TESTED/RECIEVED.txt", obtainedText);
lblOutput.Text = obtainedText;
ASCIIEncoding asen = new ASCIIEncoding();
lblOutput.Text = lblOutput.Text +" "+ ("The string was recieved by the server.");
lblOutput.Text = lblOutput.Text +" "+ ("\r\nSent Acknowledgement");
}
Client: C# Windows application
private void btnSend_Click(object sender, EventArgs e)
{
try
{
TcpClient tcpClient = new TcpClient();
int port=Int32.Parse(txtPort.Text.Trim());
tcpClient.Connect(txtIpAddress.Text, port);
lblStatus.Text = ("Connected");
Stream stm = tcpClient.GetStream();
ASCIIEncoding asen = new ASCIIEncoding();
byte[] bytesToSend = asen.GetBytes(txtData.Text);
lblStatus.Text = ("Transmitting.....");
stm.Write(bytesToSend, 0, bytesToSend.Length);
byte[] bb = new byte[100];
int k = stm.Read(bb, 0, 100);
for (int i = 0; i < k; i++)
{
txtaResponse.Text = txtaResponse.Text + "\n" + "Res... " + new DateTime() + " " + Convert.ToChar(bb[i]);
Console.Write(Convert.ToChar(bb[i]));
}
tcpClient.Close();
}
catch (Exception ex)
{
lblStatus.Text = ("Connected");
txtaRequest.Text = txtaRequest.Text + "\n" + "Err... " + new DateTime() + " " + ex.StackTrace;
}
}
My current questions are:
Is my assumption correct? If not how should I do it?
I have tried to save it using the above code but I didn't got the file.
What is the advantage and disadvantage of using UDP in comparison TCP for tracking applications?
I have browsed well, but I couldn't find a place for a good start. And, as I have no experience in such applications, I couldn't debug my application.
My current questions are:
Is my assumption correct? If not how should I do it?
Yes, your basic assumptions are correct. The server would open a listening port and then the client could connect to this port and drop off data as needed. You can have the server log this to a file for later review too.
I have tried to save it using the above code but I didn't got the
file.
Is the file already created? The method you have will fail if the file is not existent on the system.
What is the advantage and disadvantage of using UDP in comparison TCP
for tracking applications?
UPD is less expensive in terms of network setup. It is the "fast and dirty" method of communication. The downside is that you may not get every message properly delivered. In some applications, this just doesn't matter and the benefits are worth this cost.
Now a few things I'd change:
Change IPAddress.Parse(txtIpAddress.Text) to IPAddress.Any
This will allow your listener the broadest ability to catch incoming messages and will most likely not effect other systems (since this is essentially your first networking program).
You'll also want to make your listener spawn a thread to handle the file writing and then go back to listening. This is a very standard practice and allows for servers to handle multiple connections.
It is difficult to comprehensively answer this, as a good answer would require detailed knowledge about the product. I suggest that you contact the manufacturer / reseller for support.
A few general points:
Sending commands over network to the device requires that you are able to connect to the device from internet. This is not always easy over GSM network, as the operators may block all incoming traffic. The manufacturer may have provided solutions for this.
If you can connect to the device, the protocol that is used to give commands (assuming that such protocol is built-in) will also contain a mechanism to receive any responses.

ASP.Net Web API - Authorization header blank

I am having to re-write an existing REST API using .NET (originally written with Ruby). From the client's perspective, it has to work exactly the same way as the old API - i.e. the client code mustn't need to change. The current API requires Basic Authentication. So to call the old API, the following works perfectly:-
var wc = new System.Net.WebClient();
var myCache = new CredentialCache();
myCache.Add(new Uri(url), "Basic", new NetworkCredential("XXX", "XXX"));
wc.Credentials = myCache;
var returnBytes = wc.DownloadData("http://xxxx");
(I have had to ommit the real URL / username / password etc for security reasons).
Now I am writing the new API using ASP.Net Web API with MVC4. I have a weird problem and cannot find anybody else with exactly the same problem. In order to support Basic Authentication, I have followed the guidelines here:
http://sixgun.wordpress.com/2012/02/29/asp-net-web-api-basic-authentication/
One thing, I put the code to "hook in the handler" in the Global.asax.cs file in the Application_Start() event (that wasn't explained so I guessed).
Anyway, if I call my API (which I have deployed in IIS) using the above code, the Authorization header is always null, and the above fails with 401 Unauthorized. However, if I manually set the header using this code, it works fine - i.e. the Authorization header now exists and I am able to Authenticate the user.
private void SetBasicAuthHeader(WebClient request, String userName, String userPassword)
{
string authInfo = userName + ":" + userPassword;
authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo));
request.Headers["Authorization"] = "Basic " + authInfo;
}
.......
var wc = new System.Net.WebClient();
SetBasicAuthHeader(request, "XXXX", "XXXX");
var returnBytes = wc.DownloadData("http://xxxx");
Although that works, it's no good to me because existing users of the existing API are not going to be manually setting the header.
Reading up on how Basic Authentication works, the initial request is meant to be anonymous, then the client is returned 401, then the client is meant to try again. However if I put a break point in my code, it will never hit the code again in Antony's example. I was expecting my breakpoint to be hit twice.
Any ideas how I can get this to work?
You're expecting the right behavior. System.Net.WebClient does not automatically include the Authorization headers upon initial request. It only sends them when properly challenged by a response, which to my knowledge is a 401 status code and a proper WWW-Authenticate header. See here and here for further info.
I'm assuming your basic authentication handler is not returning the WWW-Authenticate header and as such WebClient never even attempts to send the credentials on a second request. You should be able to watch this in Fiddler or a similar tool.
If your handler did something like this, you should witness the WebClient approach working:
//if is not authenticated or Authorization header is null
return base.SendAsync(request, cancellationToken).ContinueWith(task =>
{
var response = task.Result;
response.StatusCode = HttpStatusCode.Unauthorized;
response.Headers.Add("WWW-Authenticate", "Basic realm=\"www.whatever.com\"");
return response;
});
//else (is authenticated)
return base.SendAsync(request, cancellationToken);
As you noticed, if you include the Authorization headers on every request (like you did in your alternative approach) then your handler already works as is. So it may be sufficient - it just isn't for WebClient and other clients that operate in the same way.

Email using System.Net.Mail through Google Apps Timing out

I have a ASP.NET 4.0 web application, which the HR team uses to send out surveys to employees. Since we use a Google Apps, I am trying to send these survey emails through the Google Apps Account.
I have used the following settings to send out emails.
Host - smtp.gmail.com
Port - 587
EnableSsl=true
along with my username and password.
This is the code for sending out emails.
using (SmtpClient smtp = new SmtpClient())
{
smtp.Timeout = 0;
smtp.Send(message);
}
The settings are in the web.config and are read from there.
Now my issue..
The hr team selects multiple users to send the survey to. They could just select 1 or maybe up to 100 at a time to send out surveys. Since each survey link has to be different, I iterate the list of users and email them.
Now after the application send out a maximum of 12 emails, it stops sending out any more. The next email it tries to send it throws an error.
Message = The operation has timed out.
Status Code =GeneralFailure
Stack Trace = at System.Net.Mail.SmtpClient.Send(MailMessage message)
at ABC.Business.Mail.SendMail(MailMessage message, String& errorMessage)
Then onwards if I retry again it throws an error
Message = Failure sending mail.
Status Code =GeneralFailure
Stack Trace = at System.Net.Mail.SmtpClient.Send(MailMessage message)
at ABC.Business.Mail.SendMail(MailMessage message, String& errorMessage)
If its come to this state, the only way out is to retart IIS. If I restart IIS, it starts working fine again for the next 12 odd.
What could be the issue? Please help.
You shouldn't set the Timeout to zero.
Its default is 100,000mS (100 seconds), try to leave it at that at least.
System.Net.Mail only supports "Explicit SSL".
Explicit SSL
System.Net.Mail only supports "Explicit SSL". Explicit SSL starts as unencrypted on port 25, then issues a STARTDLS and switches to an Encrypted connection. See RFC 2228.
Explicit SLL would go something like: Connect on 25 -> StartTLS (starts to encrypt) -> authenticate -> send data
If the SMTP server expects SSL/TLS connection right from the start then this will not work.
Implicit SSL
There is no way to use Implicit SSL (SMTPS) with System.Net.Mail. Implicit SSL would have the entire connection is wrapped in an SSL layer. A specific port would be used (port 465 is common). There is no formal RFC covering Implicit SSL.
Implicit SLL would go something like: Start SSL (start encryption) -> Connect -> Authenticate -> send data
This is not considered a bug, it’s a feature request. There are two types of SSL authentication for SMTP, and we only support one (by design) – Explicit SSL.
Demo Code:
*
protected void Btn_SendMail_Click(object sender, EventArgs e)
{
try
{
var fromAddress = "xyz#gmail.com";
var toAddress = "abc#gmail.com";
const string fromPassword = "xxxxxxxx";
string subject = "Sending Demonstration";
string body = "From: " + txtFrom.Text + "\n";
var smtp = new System.Net.Mail.SmtpClient();
{
smtp.Host = "smtp.gmail.com";
smtp.Port = 25;
smtp.EnableSsl = true;
smtp.Credentials = new NetworkCredential(fromAddress, fromPassword);
}
smtp.Send(fromAddress, toAddress, subject, body);
Response.Write("<script language=javascript> alert('send')</script>");
}
catch (Exception ex)
{
txtBody.Text = ex.Message;
}
}
*
This Code Is Working Without Any Error!!!!
Chris, TimeOut makes ASP.NET application to wait for the request to perform before it shutting down automatically. So, If you give timeOut as zero, ASP.NET will not wait for the request to perform and it will throw error as operation has timed out.
TimeOut should be atleast 180 seconds.
Thanks.

Resources