smtp clients `SendAsync()` method - asp.net

Protected Sub btnLocalSubmit_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnLocalSubmit.Click
Dim logic = New connections
logic.emailsToSend(User.Identity.Name, getURL, reportedBy)
SendAsync()
Response.Redirect(getRedirectionPath, False)
Catch ex As Exception
Response.Write(ex.Message)
Finally
_con.Close()
_con.Dispose()
_sqlComm.Dispose()
End Try
End Sub
Sub SendAsync()
Dim _con As New SqlConnection(ConfigurationManager.ConnectionStrings("CitizenJDBConnectionString").ConnectionString)
Dim _sqlDataAdapter As New SqlDataAdapter("SELECT * FROM EmailSender", _con)
Dim _table As New System.Data.DataTable
Try
_con.Open()
_sqlDataAdapter.Fill(_table)
_con.Close()
For i As Integer = 0 To _table.Rows.Count - 1
Dim AppPath As String = Request.PhysicalApplicationPath
Dim sr As New StreamReader(AppPath & "EmailTemplates/NewReport.txt")
Dim message As New MailMessage()
message.IsBodyHtml = True
message.From = New MailAddress("admin#xxxx.com")
message.To.Add(New MailAddress(_table.Rows(i).Item(1)))
message.Subject = "New User registration !"
message.Body = sr.ReadToEnd()
sr.Close()
message.Body = message.Body.Replace("<%ReporterName%>", _table.Rows(i).Item(3))
message.Body = message.Body.Replace("<%ReportURL%>", _table.Rows(i).Item(2))
Dim client As New SmtpClient()
client.Host = "smtp.xxxxx.com"
'smtp.gmail.com
client.Port = 25
client.UseDefaultCredentials = True
client.Credentials = New System.Net.NetworkCredential("admin#xxxx.com", "123456")
'client.EnableSsl = True
Dim userState As Object = message
'wire up the event for when the Async send is completed
AddHandler client.SendCompleted, AddressOf SmtpClient_OnCompleted
client.SendAsync(message, userState)
Next
Catch ex As Exception
Response.Write(ex.Message)
End Try
End Sub 'SendAsync
Public Sub SmtpClient_OnCompleted(ByVal sender As Object, ByVal e As AsyncCompletedEventArgs)
'Get the Original MailMessage object
Dim message As MailMessage = CType(e.UserState, MailMessage)
'write out the subject
Dim subject As String = message.Subject
If e.Cancelled Then
Console.WriteLine("Send canceled for mail with subject [{0}].", subject)
End If
If Not (e.Error Is Nothing) Then
Console.WriteLine("Error {1} occurred when sending mail [{0}] ", subject, e.Error.ToString())
Else
Console.WriteLine("Message [{0}] sent.", subject)
End If
End Sub 'SmtpClient_OnCompleted
I am using the smtp clients SendAsync() function to send out emails asynchronously...but this function does not work ...why?? i do not get any email..when i send it Synchronously...i get the emails, this means my settings are correct...so what is wrong with the SendAsync() method??

I do this all the time, and after years of doing this I suggest a (2) fold solution to your problem:
Refactor the actual sending email code (System.Net stuff) into a WCF service or separate .dll (I prefer the service).
Continue to use your asynchronous delegate call from your ASP.NET page but do so in a 'fire-and-forget' manner where you do not wire up any callbacks.
You might say you need to know if something went wrong with sending the email. Let the WCF service that sends the emails handle this. Do any logging in the service. After all that's all you were really doing anyways was logging. If you need to get fancier with a workflow if the email fails, there are ways that your ASP.NET can be flagged, but I think you will find that once the service to send the emails is stable, you will have very few problems.
In fact I have been doing this exact method for years using a service called by ASP.NET to send emails and have sent 10 of thousands of differing emails and never had any problem with this fire-and-forget design.
And lastly, setting the page Async=True makes the page act overall synchronously in the end by blocking the main thread until all asynchronous process are completed. This can make the pages very slow to load and is typically not desired.

Related

How can I send an email with my vb.net code?

I am using asp.net / vb.net. I want to send an email. My code does not send an email as it is. I am wondering what I am doing wrong here.
I created a file called email.text that holds the email template. The rest of the code to send the email is below. I removed personal information from my code.
I setup the SMTP connection as such:
Private SMTPClientConnection As SmtpClient
Sub New()
SMTPClientConnection = New SmtpClient
SMTPClientConnection.Host = "HOSTHERE"
SMTPClientConnection.Port = PORTHERE
SMTPClientConnection.DeliveryMethod = SmtpDeliveryMethod.Network
End Sub
Then I created a function to send the email:
Private Shared Function SendEmail(ByVal emailUser As String, ByVal bodyMessage As List(Of String), ByVal priority As MailPriority) As Boolean
Dim functionReturnValue As Boolean = False
Try
If Not String.IsNullOrWhiteSpace(emailUser) Then
If Regex.IsMatch(emailUser, "^([a-zA-Z0-9]+([\.+_-][a-zA-Z0-9]+)*)#(([a-zA-Z0-9]+((\.|[-]{1,2})[a-zA-Z0-9]+)*)\.[a-zA-Z]{2,6})$") Then
Using SMTPClientConnection
Dim smtpMessage As MailMessage = New MailMessage()
Dim _with1 = smtpMessage
_with1.[To].Add(New MailAddress(emailUser))
_with1.From = New MailAddress("Test Email" & " <email#email.com>")
_with1.ReplyToList.Add(New MailAddress("email#email.com"))
_with1.Subject = "Test Email"
_with1.Priority = priority
Dim htmlView As AlternateView = AlternateView.CreateAlternateViewFromString(bodyMessage(0), Nothing, "text/html")
Dim plainView As AlternateView = AlternateView.CreateAlternateViewFromString(bodyMessage(1), Nothing, "text/plain")
_with1.AlternateViews.Add(plainView)
_with1.AlternateViews.Add(htmlView)
SMTPClientConnection.Send(smtpMessage)
Return True
End Using
Else
Throw New SmtpException("Invalid email.")
End If
End If
Catch ex As Exception
End Try
Return functionReturnValue
End Function
I use the function on my code here:
Dim plainBody As String = File.ReadAllText(HttpContext.Current.Server.MapPath("email.txt"))
plainBody = plainBody.Replace("%Name%", emailName)
Dim emailBody As List(Of String) = New List(Of String)(New String() {plainBody})
SendEmail("email#email.com", emailBody, MailPriority.Normal)
The compiler error message is clear. The variable SmtpClientConnection is an instance variable (it exists as a different entity in any class instance where is declared) but you are trying to use inside a Shared method (a method that exists without a class instance). Inside this kind of methods you cannot use instance variables because you don't have an instance from which the method could pick the variable value and use it.
The solution could be to remove the Shared keyword from the method and then, whenever you want to call the method you need to create an instance of the class where the instance variable SmtpClientConnection is initialized and ready to be used in the following call to the SendMail method.
However, you could still use the Shared method but should remove the instance variable and create it inside the SmtpClient method:
Private Shared Function SendEmail(ByVal emailUser As String, ByVal bodyMessage As List(Of String), ByVal priority As MailPriority) As Boolean
Dim functionReturnValue As Boolean = False
Try
If Not String.IsNullOrWhiteSpace(emailUser) Then
If Regex.IsMatch(emailUser, "^([a-zA-Z0-9]+([\.+_-][a-zA-Z0-9]+)*)#(([a-zA-Z0-9]+((\.|[-]{1,2})[a-zA-Z0-9]+)*)\.[a-zA-Z]{2,6})$") Then
Dim SMTPClientConnection As SmtpClient = New SmtpClient
SMTPClientConnection.Host = "HOSTHERE"
SMTPClientConnection.Port = PORTHERE
SMTPClientConnection.DeliveryMethod = SmtpDeliveryMethod.Network
Using SMTPClientConnection
Dim smtpMessage As MailMessage = New MailMessage()
......
SMTPClientConnection.Send(smtpMessage)
Return True
End Using
Else
Throw New SmtpException("Invalid email.")
End If
End If
Catch ex As Exception
' No point in catching an exception and doing nothing here.
' You can log the exception somewhere and then throw it again
LogException(ex)
Throw
' or just remove the try/catch block.
End Try
Return functionReturnValue
End Function
In this way the variable is created only when needed and destroyed as well when the using statement ends. Take also note of the comments relative to the Try/Catch block.

Managing licenses for Office 365 in vb.net

I am trying to run Office365 cmdlets in a vb.net webservice project.The code is:
Public Function ExcutePowershellCommands() As ObjectModel.Collection(Of PSObject)
Try
Dim userList As ObjectModel.Collection(Of PSObject) = Nothing
Dim initialSession As InitialSessionState = InitialSessionState.CreateDefault()
initialSession.ImportPSModule(New String() {"MSOnline"})
Dim O365Password_secureString As New System.Security.SecureString()
Dim O365Password As String = "password"
For Each x As Char In O365Password
O365Password_secureString.AppendChar(x)
Next
Dim credential As New PSCredential("username", O365Password_secureString)
Dim connectCommand As New Command("Connect-MsolService")
connectCommand.Parameters.Add((New CommandParameter("Credential", credential)))
Dim getCommand As New Command("Get-MsolUser")
Using psRunSpace As Runspace = RunspaceFactory.CreateRunspace(initialSession)
psRunSpace.Open()
For Each com As Command In New Command() {connectCommand, getCommand}
Dim pipe As Pipeline = psRunSpace.CreatePipeline()
pipe.Commands.Add(com)
Dim results As ObjectModel.Collection(Of PSObject) = pipe.Invoke()
Dim [error] As ObjectModel.Collection(Of Object) = pipe.[Error].ReadToEnd()
If [error].Count > 0 AndAlso com.Equals(connectCommand) Then
Throw New ApplicationException("Problem in login! " + [error](0).ToString())
Return Nothing
End If
If [error].Count > 0 AndAlso com.Equals(getCommand) Then
Throw New ApplicationException("Problem in getting data! " + [error](0).ToString())
Return Nothing
Else
userList = results
End If
Next
psRunSpace.Close()
End Using
Return userList
Catch generatedExceptionName As Exception
Throw
End Try
End Function
When Connect-MsolService is run, I get this error message:
There was no endpoint listening at https://provisioningapi.microsoftonline.com/provisioningwebservice.svc that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details.
I can run this function successfully within a windows App. I think some thing might be wrong in IIS. any idea?

Sending e-mail by System.Net.Mail.SmtpClient causes 'Mailbox unavailable, Spam Rejected'

In a web application using asp.net 4.0, I use the class System.Net.Mail.SmtpClient to send email.
This is my code:
Shared Function InviaMail(ByVal toAddress As String, ByVal TestoMsg As String, ByVal TestoSubject As String) As Boolean
Dim from As New MailAddress("xxx#xxx.pro", "xxx.pro")
Dim toDest As New MailAddress(toAddress, "")
Dim mm As New MailMessage(from, toDest)
Dim altView As AlternateView
altView = AlternateView.CreateAlternateViewFromString(TestoMsg, Nothing, MediaTypeNames.Text.Html)
mm.AlternateViews.Add(altView)
mm.Subject = TestoSubject
mm.Body = TestoMsg
mm.IsBodyHtml = True
Dim smtp As New SmtpClient
Try
smtp.Send(mm)
mm.Dispose()
mm = Nothing
smtp.Dispose()
smtp = Nothing
Return True
Catch ex As Exception
Return False
End Try
End Function
For some time now, whenever I try to send an email I get this error:
Mailbox unavailable. The server response was: 5.2.0 Jhw61q00C2SXeFl01 Spam Rejected
I searched for hours for a solution, but did not find any information.
Please help me understand what is going on, and why I'm getting this error. If you need more information, I will provide it, but please try to help me.
After more tests, I think the problem is due to the raising of the anti-spam policy of internet services providers. I will ask for this to my provider.

How to send multiple emails with ASP.NET VB.net

How do I set the code below to generate multiple emails like with a reminder every 15 minutes? Thank you for any guidance.
Private Sub SendEmail(ByVal pharmEmail As String, ByVal backupEmail As String)
Dim smtpClient As New System.Net.Mail.SmtpClient()
Dim message As New System.Net.Mail.MailMessage()
Try
Dim fromAddress As New System.Net.Mail.MailAddress(WebConfigurationManager.AppSettings("EmailFromAddr"), WebConfigurationManager.AppSettings("EmailFromName"))
message.From = fromAddress
message.To.Add(pharmEmail)
message.Subject = WebConfigurationManager.AppSettings("EmailSubject")
message.Priority = Net.Mail.MailPriority.High
If (WebConfigurationManager.AppSettings("backupEnabled") = True) Then
message.CC.Add(backupEmail)
End If
message.IsBodyHtml = True
Dim orderURL As New HyperLink
orderURL.Text = "here"
orderURL.NavigateUrl = "http://" & WebConfigurationManager.AppSettings("ServerName") & "/User/ReviewOrder.aspx?orderID=" & webOrderID
message.Body = "An order was created using the account of " + Profile.FirstName.ToString() + " " + Profile.LastName.ToString() + ". " + WebConfigurationManager.AppSettings("EmailBody") + "<a href='" + orderURL.NavigateUrl + "'>here.</a>"
'message.Body = WebConfigurationManager.AppSettings("EmailBody") & " " & orderURL.
smtpClient.Send(message)
Catch ex As Exception
ErrorHandler.WriteError(ex.ToString)
Throw ex
End Try
I agree with comments on the scheduler. If you don't like that you can create a windows service that does this. This will solve if you want to fire the routine every X minutes.
You don't have enough code here to send out emails, so you have to wrap this with some logic that fires the routine with the email information you want. More than likely, this is stored in a database (recipients, email) or some other persistent store.
I do caution the idea of sending reminders every 15 minutes to the same people, as you are more than likely to piss them off (unless that is your intent?).
Thank you all for you contributions. I have decided to create a SSIS package with a SQL and Send Email tasks. The SQL task check for new orders placed and the Send Email task sends reminder to users in a scheduled time.

My code isn't giving the user's the correct feedback. Any ideas how to fix this?

I have a very simple code that invokes a stored procedure. The stored proc is used for sending out reminders to user's on expiring account.
When a user enters correct email address, the user gets a reminder email with the message, "Reminder sent successfully"
This is exactly what we want.
However, if the user enters an invalid email address, the user still sees same message, "Reminder sent successfully"
This is not good.
Can you please help with what I am doing wrong?
Please see entire (actual) code below:
Protected Sub BtnSubmit_Click(ByVal sender As System.Object, ByVal e As System.Web.UI.ImageClickEventArgs) Handles BtnSubmit.Click
Dim oConnection As SqlConnection = New SqlConnection(ConfigurationManager.ConnectionStrings("sConnectionString").ConnectionString)
Dim oCommand As SqlCommand = New SqlCommand()
Try
oConnection.Open()
oCommand.Connection = oConnection
oCommand.CommandText = "AcountExpiration"
oCommand.CommandType = CommandType.StoredProcedure
oCommand.Parameters.Add(New SqlParameter("#Email", Data.SqlDbType.VarChar, 50)).Value = Email.Text
Dim adpt As New SqlDataAdapter(oCommand)
Dim ds As New DataSet()
adpt.Fill(ds)
oCommand.ExecuteReader()
lblMsg.Text="Reminder successfully sent"
Catch ex As SqlException
Response.Write("<SCRIPT LANGUAGE='JavaScript'>alert('" + ex.Message + "')</SCRIPT>")
Finally
oConnection.Close()
End Try
End Sub
c# solution is welcome as well.
Dim scmd As SqlCommand = New SqlCommand("AcountExpiration", Conn)
scmd.CommandType = CommandType.StoredProcedure
scmd.Parameters.AddWithValue("#Email", Email.Text)
'Dim r As SqlDataReader = scmd.ExecuteReader()
Dim validEmail As Boolean = False
Dim reader As SqlDataReader = scmd.ExecuteReader()
While reader.Read()
'if we are here then something got returned.
'so probably a valid email.
validEmail = True
End While
If validEmail = True Then
lblMsg.Text = "Success"
Else
lblMsg.Text = "email does not exit on our system"
End If
You have a couple of different options as I see it.
Have the sproc throw an error if the email address isn't valid.
Have validation on the dataset to check and make sure you are getting back the expected values. Only display the success message if there was actually a success.
I would not use a SqlDataAdapter or Dataset for this. just use the SqlDataReader
bool validEmail = false;
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
//if we are here then something got returned.
//so probably a valid email.
validEmail = true;
}
Or use ExecuteScalar
bool validEmail = Convert.ToBoolean(command.ExecuteScalar());
then
if(validEmail)
{
}
else
{
}
UPDATE
Will add an update for this as some people don't realise that certain code wont magically work. I have already included links for ExecuteScalar and ExecuteReader to show how to use these methods.
If you wanted to use ExecuteScalar you would have to change your stored procedure to return a value that could then be parsed as a Boolean.
The above methods is simply for checking if an email exists in the DB. No this does not valdate an email address, as I would expect that to occur before this code would be reached.

Resources