I am using SmtpClient (.NET 3.5, VS 2008) for mass mailings. The code below starts with about 2 seconds per send and deteriorates to more than 20 seconds per send after the foreach loop has processed about 30 addresses and proceeds to deteriorate. Any ideas?
Jim
// Setup Client
SmtpClient client = new SmtpClient(smtpHost, 587);
client.Credentials = new NetworkCredential(smptLogin, smtpPassword);
// Send mail
foreach (string address in addresses)
{
MailMessage message = BuildMessage(body);
message.To.Clear();
message.To.Add(new MailAddress(address));
client.Send(message);
}
The provider running the host you're connecting to might be implementing throttling as an anti-spam measure.
It looks like the content of your mail doesn't change per-recipient. In an enterprise environment, I would send a single mail, not dozens, and add recipients to the Bcc list. You might try this.
Related
I recently tried my hands at the new Gmail API. And all seems to work fine except one thing. My issue is as follows:
I working on a receptionist project that may need to generate more than one email in less than a minute during busy hours. So just for testing purposes I run the following code which works fine:
if __name__ == '__main__':
service = setup() //Simply an helper function to do the basic credential check. Works fine!
print('service:'+str(service))
for counter in range(1, 10):
print('Sending message '+ str(counter))
message = create_message(<SENDER_EMAIL_ID>,<RECEIVER_EMAIL_ID>, "Email Number: "+ str(counter) , "Sample text")
response = send_message(service, 'me' , message)
print(response)
The setup() function is as follows:
credentials = get_credentials()
http = credentials.authorize(httplib2.Http())
service = discovery.build('gmail', 'v1', http=http)
Now, when I run the code say thrice consecutively in less than a minute, the code runs fine and I am able to see all the 27 emails in the sent folder of the SENDER_EMAIL_ID using a web browser. And thus Gmail API is sending all the messages through whenever a request is being made. However, only some of these emails are being received at the RECEIVER_EMAIL_ID and rest are just being dropped.
However, if I run the program with say 2-5 minutes delay then all the mails are being received.
I have no idea why this is.
Any help would be really appreciated. :)
To expound more on #ken-y-n's response in the comments section, GMail API has usage limits. Specifically for this product, Daily usage is about
1 Billion quota units / day
250 quota units / user / second
You may have encountered the rateLimitExceeded error during your tests.
Since you're sending emails thru a loop, it will cost you about 100 units when calling send (plus other costs depending on the methods you're calling). This is the reason why some emails seemed to be dropped. You can counter this by implementing exponential backoff on the messages that failed to send.
Another alternative instead of running it thru a loop, is to use Batch requests which groups your API calls together to reduce the number of HTTP connections your app making.
Gives In my windows Phone 8.1 application and using MvvmLight ,
I am sending two doubles to my web service, it works on Emulator in the following code;
DispatcherHelper.CheckBeginInvokeOnUI(async () =>
{
Geolocator geo = new Geolocator();
Geoposition pos = await geo.GetGeopositionAsync();
HttpClient client = new HttpClient();
var request = await client.GetAsync(new Uri("http://..+double a,+ double b, UriKind.RelativeOrAbsolute));
var response = await request.Content.ReadAsStringAsync();
BranchList = JsonConvert.DeserializeObject<List<Branch>>(response);
}
than, I am switch on my phone's GPS and Wifi but it gives bad request.
1) Did you look at your web service to check if you find a difference between the request from emulator and real device?
2) Disable carrier on real phone and try with network, and check again on webservice side too, to see if you find a difference in the request?
3) Another way, with Wireshark you can check your request between real device and emulator (but is more work and complicated than 1 and 2 )
I'm using a HttpClient to send a SOAP request to an webservice to query some data. For some webservice parameters the execution of the webservice takes longer than 5 minutes and after 5 minutes I get an java.net.SocketException: Connection reset.
I think that the error occures because the connection idles for more than 5 minutes and then a firewall caps the connection.
Is there a way to send a keep-alive package for a http post request or something to keep the connection alive? (I need a client-side solution if possible)
If you google for HttpClient keep-alive you find a lot of topics regarding reusing a connection. In my case I only want to keep the connection alive until I get a response.
Method to execute the SOAP request:
def executeSOAPRequest(String url, String content, String soapAction, Integer timeout) {
def retVal = new SoapResponse();
PostMethod post = new PostMethod(url);
RequestEntity entity = new StringRequestEntity(content,"ISO-8859-1","ISO-8859-1");
post.setRequestEntity(entity);
post.setRequestHeader("SOAPAction", soapAction);
HttpClient httpclient = new HttpClient()
httpclient.setTimeout(timeout)
try {
retVal.httpResponse = httpclient.executeMethod(post);
retVal.httpResponseBody = post.getResponseBodyAsString();
} catch(Exception e){
... exception handling ...
} finally {
... finally stuff ...
}
return retVal;
}
Currently the HttpClient v3.1 is used.
5 minutes are an eternity in telecommunications, this days one giga can be transferred in less time, and keeping a connection idle consumes resources not only in the ending machines but in the intermediate nodes such as routers and firewalls.
So IMHO you shouldn't try to keep the connection alive for so long, especially if you don't manage the networks you are using (ie, firewalls can have their own timeouts and kill your connection), you should reduce the time the server needs to respond, or use other asynchronous communication mechanism.
I ran into an issue where my mail server only accepts 100 connections to the server every 5 minutes. My current code loops over my database, calling cfmail for each person on the list. I suppose the problem is im opening a new connection each time I use cfmail?
<CFLOOP QUERY="Customer" >
<!---send mail to Admin ----->
<cfmail to = "#cstEmail#"
from = "#FORM.fromAddressEmail#"
subject = "#FORM.subjectEmail#"
server = "#var.mailserver#"
port= "#var.mailport#"
username="#var.mailuser#"
password="#var.mailpass#"
failto="#var.failEmail#
type="html"
>
What I ran into was only 100 mails were being sent at a time, the rest were sent to cf's undelivered folder. I would send them to spool and again 100 would get through..
Now, I've read in older versions of cf there is a checkbox in cf administrator to "maintain connection" -Im running cf9 and dont see this option.
Would using cfmail's query attribute, force cfmail to only connect to the mail server once to send all the emails?
<cfmail query="Customer"
from = "#FORM.fromAddressEmail#"
to = "#cstEmail#"
subject = "#FORM.subjectEmail#">
Im not even sure how to test this without sending a couple hundred emails. Any thoughts if this is a viable solution to the problem?
Thanks for your help!
Biscotti
I ended up compromising by using a scheduled task to move the files every 5 minutes back over to the Spool dir from the Undelivr dir. Im not thrilled with this solution, but it works.
Thanks to Russ's Respooler extension. http://cfrespooler.riaforge.org/
By using the above code to call the QUERY within CFMAIL I only succeeded in speeding up the client side process. The mail server still rejected the mail after the 100th connection - leading me to determine there is no server side benefit to this method over simply looping CFMAIL like in my first example. I seems the only answer is to run the code within the enterprise edition of the cf environment, one that has the "maintain connection" feature enabled.
Here is my setup right now:
connection = mail.get_connection()
maillist = []
# my real setup is a little more complex for-loop, but basicly I add all recipients to a list.
for person in object_list:
mail_subject = "Mail subject here"
mail_body = "Mail body text...bla bla"
email_sender = "me#example.com"
maillist.append((mail_subject, mail_body, email_sender, [person.email]))
#send_mass_mail wants a tuple, so we convert the list
mailtuple = tuple(maillist)
mail.send_mass_mail(mailtuple, fail_silently=False, connection=connection)
However, the forloop iterates over 1000+ objects/persons and when I try this method I'm able to send 101 emails, and then it stops. No errors (as I can see) anywhere.
A fellow developer mentioned that maybe the POST size was too big? Any ideas from the SO-community?
Your SMTP server probably has some send limits. For example, I believe Gmail limits outgoing mail to 100 recipients.
As Micah suggested, there is a good chance you are hitting server limits.
Generally, when dealing with mass mail, it is always a good idea to throttle the sending. Doing 50 mails every 5 seconds for 300 seconds beats 3000 mails at once for many practical reasons including smtp server limitations.
Since you mentioned a POST limit - do you send out the emails in a view? I'm wondering how you handle canceled requests in your setup.
I'm using a management command to send out 1000+ newsletters. But instead of send_mass_mail i use the normal send method in a loop. It takes about 5 minutes (haven't a correct count atm) to send out the mails and i haven't run into any server limits yet.
My plan is to switch to celery to handle sending through a web interface. Perhaps you want to have a look at it in case you haven't already.
http://celeryproject.org/