email containing with SQL - c#

I have a button called "lnkupdate_click" basically all it does when you click is access a table called "tbl_security" and from there it will update the field "pass" with a random 4 digit number where the field "patrol" = 1 or true.
an example is shown below;
Code Pass Patrol
TES 1234 1
ASD 4321 1
MOR 6789 1
SAI 0959 1
The bit I am stuck on is this: All I want it to do from here is send the updated info from the database in an email. So basically to generate me an email containing all of the information in the table above. However I keep getting a red line underneath my "foreach" loop with this error message.
"foreach statement cannot operate on variables of type 'int' because 'int' does not contain a public definition for 'GetEnumerator'"
My code is below:
protected void lnkUpdate_Click(object sender, EventArgs e)
{
{
string queryUpdateAllFields;
string queryGetAllUpdatedField;
StringBuilder sb = new StringBuilder();
queryGetAllUpdatedField = #"update tbl_Security set
Pass = round(rand(CAST(CAST(NEWID() AS VARBINARY(4)) AS SMALLINT))* 9000,0) + 1000
WHERE Patrol = 1";
queryGetAllUpdatedField = #"SELECT Code, Pass, Patrol
FROM tbl_Security
WHERE Patrol = 1";
var random = new Random();
//queries to update and retrieve
SqlHelper.ExecuteSqlNonQuery(queryUpdateAllFields);
var results = SqlHelper.ExecuteSqlNonQuery(queryGetAllUpdatedField);
//loop over the results and append to StringBuilder instance.
sb.Append("Below are all the fields that have been updated: <br /><br />");
foreach(var r in results)
{
sb.AppendLine("<hr />");
sb.AppendLine("Code: " + r.Code + " Pass: " + r.Pass + " Patrol: " + r.Patrol); //for Patrol
}
//Email showing all updated pass's with codes
MailAddress to = new MailAddress("");
MailAddress from = new MailAddress("");
MailMessage message = new MailMessage(from, to);
message.Subject = "Subject Line Here";
message.Body = sb.ToString(); //attach StringBuilder - This will be built up of all the rows updated in the DataBase
SmtpClient mailClient = new SmtpClient();
mailClient.Port = 25;
//finally send message here
mailClient.Send(msg);
}
}

ExecuteSqlNonQuery returns an int not a collection which I think you are assuming.

try:
change the loop like so: for(int i= 0; i < results; i++)

Related

Appended strings in message body not being sent in email using SMTPClient() and StringBuilder()

First and foremost I am very new to C# and am sure most of my code could be cleaned up so please don't suggest it unless you are also offering help with my issue.
I am sending an email via SmtpClient(). I am trying to build the body of the email using strings which are returned from functions in loops. My issue is that the string for the body isn't building how I thought it should.
Currently, I am creating a new StringBuilder() with some default text in it. I am then running some functions and trying to add the results to the StringBuilder() object via StringBuilder.AppendLine().
Here is (some of) my code:
// Setup SMTP Client for sending mail updates
//-----------------------------------
String from_addr_text = "<removed>";
String to_addr_text = "<removed>";
String msg_subject = "Updates to USPTO searches";
StringBuilder msg_body = new StringBuilder("The following searches have received updated results:" + Environment.NewLine);
SmtpClient AlertMail = new SmtpClient
{
Port = 587,
Host = "<removed>",
EnableSsl = true,
Timeout = 10000,
DeliveryMethod = SmtpDeliveryMethod.Network,
UseDefaultCredentials = false,
Credentials = new System.Net.NetworkCredential("<removed>", "<removed>")
};
MailMessage update = new MailMessage(from_addr_text, to_addr_text, msg_subject, msg_body.ToString())
{
BodyEncoding = UTF8Encoding.UTF8,
IsBodyHtml = false,
DeliveryNotificationOptions = DeliveryNotificationOptions.OnFailure
};
...
// Process data from api for Assignor
//-----------------------------------
bool isUpdated = false;
foreach (String url in searchesByAssignorUSPTO)
{
try
{
String longName = <removed>);
String name = <removed>;
String thisHash = await GetSearchData(url, name, "Assignor");
if (DoesHashExist(thisHash))
{
Debug.WriteLine(thisHash + " already exists. No update to " + name + " search.");
}
else
{
Debug.WriteLine(thisHash + " does not exist. There is an update to " + name + " search.");
isUpdated = true;
msg_body.AppendLine(name + " as " + "Assignor" + Environment.NewLine);
}
}
catch
{
Console.WriteLine("something is broken with ASSIGNOR search dummy!");
}
}
// Process data from api for Assignee
foreach (String url in searchesByAssigneeUSPTO)
{
try
{
String longName = <removed>;
String name = <removed>;
String thisHash = await GetSearchData(url, name, "Assignee");
if (DoesHashExist(thisHash))
{
Debug.WriteLine(thisHash + " already exists. No update to " + name + " search.");
}
else
{
Debug.WriteLine(thisHash + " does not exist. There is an update to " + name + " search.");
isUpdated = true;
msg_body.AppendLine(name + " as " + "Assignee" + Environment.NewLine);
}
}
catch
{
Console.WriteLine("something is broken with ASSIGNEE search dummy!");
}
}
// Send email is search results are updated
if (isUpdated)
{
AlertMail.Send(update);
Debug.WriteLine(msg_body.ToString());
}
When the program runs and there are results returned from the loops, msg_body is printed to the output window correctly but, when the email is received the body is only: "The following searches have received updated results:".
I have tried:
changing the value of isBodyHtml to true and used <br />
instead of Environment.NewLine.
adding \n to end of stringing and removing Environment.NewLine.
changing msg_body to type String and concatenating results to msg_body using =+.
using the Append() method instead of AppendLine().
Here is a snip of the output window:
Be sure to watch the assignment of variables in your code. When you assign msg_body to the update MailMessage object, it's only inputting the one line mentioned that is being returned in the email and doesn't include the information generated by the API.
Try moving the intialization of your SmtpClient and MailMessage variables to right before the if (isUpdated) block and you should be good to go.
per #tym32167, I needed to move the instantiation of MailMessage() to AFTER my loops and functions were completed. I was creating the object before the AppendLines() methods were called and therefore they weren't being included.

c# System.ArgumentOutOfRangeException

I'm making program that sends email with some data. I know that the System.ArgumentOutOfRangeException exception means that number in the array/list doesn't exist, but i don't know what i coded wrongly.
Here's a code:
public void SendMail()
{
StreamReader sr = new StreamReader(path1);
var lineCount = File.ReadLines(path1).Count();
List<string> data = new List<string>();
for (int i = 0; i < lineCount; i++)
{
data[i] = sr.ReadLine(); //Error Comes here.
}
string finaldata = data[0] + "/n" + data[1] + "/n" + data[2] + "/n" + data[3] + "/n" + data[4] + "/n" + data[5] + "/n" +
data[6] + "/n" + data[7] + "/n" + data[8] + "/n" + data[9] + "/n" + data[10];
var fromAddress = new MailAddress("tutorialvideohd#gmail.com", "From Name");
var toAddress = new MailAddress("tutorialvideohd#example.com", "To Name");
const string fromPassword = "*****";
string subject = "Some Users Data.";
string body = finaldata;
var smtp = new SmtpClient
{
Host = "smtp.gmail.com",
Port = 587,
EnableSsl = true,
DeliveryMethod = SmtpDeliveryMethod.Network,
UseDefaultCredentials = false,
Credentials = new NetworkCredential(fromAddress.Address, fromPassword)
};
using (var message = new MailMessage(fromAddress, toAddress)
{
Subject = subject,
Body = body
})
{
smtp.Send(message);
}
}
When you do this, it's only creating an empty list:
List<string> data = new List<string>();
So if you try to assign a value using an index, you're trying to assign a value to something that doesn't exist.
Instead you should Add() as follows:
data.Add(sr.ReadLine());
EDIT:
Also, unrelated to the question asked, but I don't see you closing the StreamReader you've opened, which is always a bad practice. I suggest, instead, using a using statement which will take care of the opening and closing of the StreamReader for you. Also, getting the lineCount is redundant, you could do something like this taking advantage of the fact that you don't need to set the number of items in a list in advance.
List<string> data = new List<string>();
using (StreamReader sr = new StreamReader(path1))
{
while(!sr.EndOfStream)
data.Add(sr.ReadLine());
}
First, you have an empty list of strings, you can't fill data with by accessing the indexes, since those indexes don't yet exist. You have to use data.Add(sr.ReadLine()) to create the new index and add the value in it.
string finaldata = data[0] + "/n" + data[1] + "/n" + data[2] + "/n" + data[3] + "/n" + data[4] + "/n" + data[5] + "/n" +
data[6] + "/n" + data[7] + "/n" + data[8] + "/n" + data[9] + "/n" + data[10];
Hardcoded IDs will mean you need at least 11 items in the list and it will break if you have less. Why don't you do this instead?
string finalData = String.Join("/n", data);
This way it joins your list of strings, using the newline as a separator and doesn't matter if you have more or less items in the list.
You are setting an item in the array list that has not yet been initialized. Use the following line where the exception is thrown.
data.Add(sr.ReadLine());
You are doing the same thing twice.
This block of code:
StreamReader sr = new StreamReader(path1);
// ... you had some code here, but not relevant to the point...
for (int i = 0; i < lineCount; i++)
{
data[i] = sr.ReadLine(); //Error Comes here.
}
Populates the list data with a bunch of strings.
This block of code:
var lineCount = File.ReadLines(path1).ToList();
Populates lineCount with exactly the list of strings that you're trying to fill into data.
So just do this:
StreamReader sr = new StreamReader(path1);
var lineCount = File.ReadLines(path1).Count();
List<string> data = lineCount;
And get rid of this block of code:
for (int i = 0; i < lineCount; i++)
{
data[i] = sr.ReadLine(); //Error Comes here.
}
And notice how data is now properly filled in. You really don't need to have that StreamReader either, but hey, I don't want to rewrite your entire body of code at this point.
Key takeaway: read the documentation, try to understand what each function call is doing, especially the .NET Framework ones.

how to use session variables in email

The Title does not make brilliant sense but essentially I want to use session variables and include them within an email body within the c# code. Sending the email without session variables works fine. Is it even possible to do what I want?
REVISED CODE:
public partial class Success : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
MembershipUser userName = Membership.GetUser(User.Identity.Name);
ListBox order = (ListBox)(Session["order"]);
string name = (String)(Session["name"]);
string addressLine1 = (String)(Session["addressLine1"]);
string addressLine2 = (String)(Session["addressLine2"]);
string addressLine3 = (String)(Session["addressLine3"]);
string county = (String)(Session["county"]);
string postCode = (String)(Session["postcode"]);
SmtpClient SmtpServer = new SmtpClient("smtp.live.com");
var mail = new MailMessage();
mail.From = new MailAddress("my email");
mail.To.Add("recipient email");
mail.Subject = "Your Reciept";
mail.IsBodyHtml = true;
string htmlBody;
htmlBody = "Hi "+ userName + Environment.NewLine + Environment.NewLine +
"Here's your details: " + Environment.NewLine + Environment.NewLine
+ order + Environment.NewLine + Environment.NewLine
+ name + Environment.NewLine
+ addressLine1 + Environment.NewLine
+ addressLine2 + Environment.NewLine
+ addressLine3 + Environment.NewLine
+ county + Environment.NewLine
+ postCode + Environment.NewLine + Environment.NewLine;
mail.Body = htmlBody;
SmtpServer.Port = 587;
SmtpServer.UseDefaultCredentials = false;
SmtpServer.Credentials = new System.Net.NetworkCredential("my email", "password");
SmtpServer.EnableSsl = true;
SmtpServer.Send(mail);
}
}
also to note, Environment.NewLine does not work.
Your help would be most appreciated
It's not clear from your question where you are trying to access Session, but it is available from any code running in the web worker process (see my answer here). However, I prefer to put email logic in a separate class or even separate project.
The class can then take the input values as strings, or a type that represents your data.
// good
public void SendMail( string name, string address, etc etc )
{
// mail code here
}
// better
public void SendMail( UserInfo info )
{
}
// best
public void SendMail( UserInfo info, string template )
{
// insert the user values into a template of some sort...no hardcoding format/HTML
}
Regarding Environment.NewLine. Your string name is htmlBody, which implies you are sending an HTML email. You should use the appropriate markup instead of a newline.
for those who helped me, sorry for wasting your time. I figured it out... really stupid but I was setting the session variables incorrectly in a previous webform before therefore the session variables were null.
the reason that there was no error was (my guess), I was setting the session variables on button_click function yet also having a postbackurl. the postbackurl must have overridden the button_click function.
So, For future reference. Originally I had
string name = Session["name"].ToString();
lblName.Text = name; //this didnt work
I corrected this by
Session["name"] = lblName.Text;

how to send the gridview in email with formatting

I am developing an online ordering web application in which I have to email with perches product details to customer. I have maintain all the data in a data table and then generated the grid view pragmatically as follows
public GridView makeGridview(DataTable Dt)
{
GridView GV = new GridView();
GV.DataSource = Dt;
GV.DataBind();
return GV;
}
then adding this grid view to email
body = body.Replace("{Product_Details}", GridViewToHtml(makeGridview(Dt)));
private string GridViewToHtml(GridView gv)
{
StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
HtmlTextWriter hw = new HtmlTextWriter(sw);
gv.RenderControl(hw);
return sb.ToString();
}
This is working fine but the problem is then am unable to design it in our predefine format. This mail will be received by the customer of my website, so I need to convert in to our them.
Please guide me how to format in our them.
If there is an another way to do this then I'm open to that as well.
I would suggest you to not trust the GridView as your rendered html, but instead to use your current data-source for that (DataTable):
public GridView CreateHtmlTable(DataTable dt)
{
//Do your HTML work here, like the following:
string tab = "\t";
StringBuilder sb = new StringBuilder();
sb.AppendLine("<html>");
sb.AppendLine(tab + "<body>");
sb.AppendLine(tab + tab + "<table>");
// headers.
sb.Append(tab + tab + tab + "<tr>");
foreach (DataColumn dc in dt.Columns)
{
sb.AppendFormat("<td>{0}</td>", dc.ColumnName);
}
sb.AppendLine("</tr>");
// data rows
foreach (DataRow dr in dt.Rows)
{
sb.Append(tab + tab + tab + "<tr>");
foreach (DataColumn dc in dt.Columns)
{
string cellValue = dr[dc] != null ? dr[dc].ToString() : "";
sb.AppendFormat("<td>{0}</td>", cellValue);
}
sb.AppendLine("</tr>");
}
sb.AppendLine(tab + tab + "</table>");
sb.AppendLine(tab + "</body>");
sb.AppendLine("</html>");
}
Follow follwing code:
public void SendHTMLMail()
{
MailMessage Msg = new MailMessage();
MailAddress fromMail = new MailAddress("administrator#aspdotnet-suresh.com");
// Sender e-mail address.
Msg.From = fromMail;
// Recipient e-mail address.
Msg.To.Add(new MailAddress("suresh#gmail.com"));
// Subject of e-mail
Msg.Subject = "Send Gridivew in EMail";
Msg.Body += "Please check below data <br/><br/>";
Msg.Body += GetGridviewData(gvUserInfo);
Msg.IsBodyHtml = true;
string sSmtpServer = "";
sSmtpServer = "10.2.160.101";
SmtpClient a = new SmtpClient();
a.Host = sSmtpServer;
a.EnableSsl = true;
a.Send(Msg);
}
// This Method is used to render gridview control
public string GetGridviewData(GridView gv)
{
StringBuilder strBuilder = new StringBuilder();
StringWriter strWriter = new StringWriter(strBuilder);
HtmlTextWriter htw = new HtmlTextWriter(strWriter);
gv.RenderControl(htw);
return strBuilder.ToString();
}
Refer below doccument:
http://www.aspdotnet-suresh.com/2012/09/how-to-send-gridview-in-email-body-in.html
Honestly what you have done here (rendering a Web Forms control to an email string) seems like a bit of an unintended trick. Honestly it's not that hard to iterate through a collection and build an HTML table using a StringBuilder.
I believe that for email HTML the convention is often to use inline styles to guarantee the best compatibility with email clients. So you'd want to style your elements like so:
<table>
<tbody>
<tr style="background-color: #EE0000">
<td style="text-transform: uppercase"></td>
...
</tr>
</tbody>
</table>
In the past I've done this by creating an HTML file with everything how I want it and using placeholders like {VariableName} and then doing a string replace on the variables with their values. This way you separate your HTML view from the C# code. It'd be a little tricky with a list of items, in that case you'd have at least two HTML templates: one for the entire document and one for the item rows.
I ran into a similar issue like yours, and I got it done like this:
encapsulated the functionality in a separate HelperClass for ease of use. Used static variables and methods to keep it simple
write the HTML code to format the content of the GridView to a nice table (with zebra stripes and stuffs)
public static StringBuilder gridViewToHTML(GridView gv)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("<html>");
sb.AppendLine("<body>");
sb.AppendLine(#"<table style='padding: 10px; font-family: Verdana; font-size:11px;
border-style:solid;border-width:1px;border-color:grey;'> ");
sb.AppendLine("<tr>");
/* *** Build header of the HTML table *** */
for (int i = 0; i < gv.Columns.Count; i++)
{
sb.AppendLine("<td style='font-weight:bold;background-color:black;color:white;'>" + gv.Columns[i].HeaderText + "</td>");
}
sb.AppendLine("</tr>");
/* *** Build body of the HTML table *** */
for (int i = 0; i < gv.Rows.Count; i++)
{
sb.AppendLine("<tr>");
foreach (DataControlFieldCell gvcell in gv.Rows[i].Cells)
{
sb.AppendLine("<td style='text-align;left;'>" + gvcell.ToString() + "</td>");
}
sb.AppendLine("</tr");
}
sb.AppendLine("</table>");
sb.AppendLine("</body>");
sb.AppendLine("</html>");
return sb;
}
send the email message using the StringBuilder object as html formatting of the content, and the casual parameters (to Whom, and Subject)
public static void sendEmailMessage(StringBuilder stringBuilder, string email_ToAddress, string email_Subject)
{
DateTime now = DateTime.Now;
DateTime yesterday = DateTime.Now.AddDays(-1);
MailMessage mail = new MailMessage();
//SomeEmailAccount#yourOrganization.com must be set by your Sysadmin before using it.
mail.From = new MailAddress("SomeEmailAccount#yourOrganization.com");
mail.To.Add(email_ToAddress);
mail.Subject = $"{email_Subject} . Date #{now.ToShortDateString()}";
mail.Body = stringBuilder.ToString();
mail.IsBodyHtml = true;
NetworkCredential autentificare = new NetworkCredential();
autentificare.UserName = "SomeEmailAccount#yourOrganization.com"";
autentificare.Password = "yourPassw0rd";
SmtpClient smtp = new SmtpClient();
smtp.Host = "mail.yourOrganization.com";
smtp.UseDefaultCredentials = true;
smtp.Credentials = autentificare;
smtp.Port = 25;
smtp.EnableSsl = false;
smtp.Send(mail);
}

How can i send email one after one in a row?

In Form1 in the backgroundworkerdowork event I did:
se.SendPhotos(photofilesDir + "\\" + "photofiles.zip");
se.SendPhotos(photofilesDir1 + "\\" + "photofiles.zip");
se.SendPhotos(photofilesDir2 + "\\" + "photofiles.zip");
se.SendPhotos(photofilesDir3 + "\\" + "photofiles.zip");
In the se class SendEmail I did:
public void SendPhotos(string fileNameToSend)
{
try
{
MailAddress from = new MailAddress("test#gmail.com", "User " + (char)0xD8 + " Name",
System.Text.Encoding.UTF8);
MailAddress to = new MailAddress("test#test");
photosmessage = new MailMessage(from, to);
photosmessage.Body = "Please check the log file attachment I have some bugs.";
string someArrows = new string(new char[] { '\u2190', '\u2191', '\u2192', '\u2193' });
photosmessage.Body += Environment.NewLine + someArrows;
photosmessage.BodyEncoding = System.Text.Encoding.UTF8;
photosmessage.Subject = "Log File For Checking Bugs" + someArrows;
photosmessage.SubjectEncoding = System.Text.Encoding.UTF8;
Attachment myAttachment = new Attachment(fileNameToSend, MediaTypeNames.Application.Octet);
photosmessage.Attachments.Add(myAttachment);
SmtpClient photossend = new SmtpClient("smtp.gmail.com", 587);
photossend.SendCompleted += new SendCompletedEventHandler(photossend_SendCompleted);
photossend.EnableSsl = true;
photossend.Timeout = 10000;
photossend.DeliveryMethod = SmtpDeliveryMethod.Network;
photossend.UseDefaultCredentials = false;
photossend.Credentials = new NetworkCredential("usern", "userpass");
string userState = "test message1";
photossend.SendAsync(photosmessage, userState);
SendLogFile.Enabled = false;
fname = fileNameToSend;
}
catch (Exception errors)
{
Logger.Write("Error sending message :" + errors);
}
}
private void photossend_SendCompleted(object sender, AsyncCompletedEventArgs e)
{
photosmessage.Dispose();
if (fname == #"C:\Users\Simbalip\AppData\Local\outputphotos\photosfiles3" + "\\" + "photofiles.zip")
{
photossendended = true;
}
}
The problem in the backgroundworkerdowork it never send the last one photofilesDir3.
I used a breakpoint and its getting to : photossendended = true;
But in my email im getting only 3 files sent for me and not 4.
When I used a breakpoint on the backgroundworker and did F11 I saw that its doing the 4 sendings one after one without waiting .
Each time the photofiles.zip have different files inside.
Now I check did a breakpoint on the line:
if (fname == #"C:\Users\Simbalip\AppData\Local\outputphotos\photosfiles3" + "\\" + "photofiles.zip")
And when it get there its all the time true it does ==
fname never C:\Users\Simbalip\AppData\Local\outputphotos\photosfiles2 or 1 or photosfiles
But in the end im getting 3 different photofiles.zip files each contain different files but one of the files never sent.
Myabe I need to make somehow that when it send email it will somehow untill the first one is sent then send the next one like in Process there is WaitForExit() so maybe something like that with the emails ?
The documentation for SmtpClient alludes to the fact that it doesn't support parallel operations.
If there is an e-mail transmission in progress and you call SendAsync or Send again, you will receive an InvalidOperationException.
http://msdn.microsoft.com/en-us/library/system.net.mail.smtpclient.aspx
I would recommend not sending the next email until the SendCompleted event has been raised. This means a drastic change in your code (where each call to SendPhotos really just adds something to a collection of pending send mail operations that your process in the background)

Categories

Resources