SmtpClient.SendAsync() not receiving all messages I sent - c#

I've just written some test code looking at the System.Net.Mail.SmtpClient sending identical messages to myself.
int numClients = 10;
List<SmtpClient> mailClients = new List<SmtpClient>();
for (int i = 0; i < numClients; i++) {
mailClients.Add(new SmtpClient(smtpHost));
}
MailMessage msg = new MailMessage("myAddress#eg.com", "myAddress#eg.com", "test message", "" );
foreach (SmtpClient c in mailClients) {
c.SendAsync(msg, null);
}
This is all fine and executes without any problems except that I only receive 'n - 1' messages.
i.e. If I send 10 messages I only recieve 9 in my inbox. If I send 50 I only receive 49 etc.
Note: If I change the code to use a blocking Send then I will always receive the right number of messages.
e.g.
foreach (SmtpClient c in mailClients) {
c.Send(msg);
}
Any ideas?

Here are a few observations that may help:
Only create one SmtpClient.
Create multiple messages instead.
SmtpClient implements IDisposable. Wrap it in using.
MailMessage also implements IDisposable.
I suspect you may be running into a bug/issue with multiple SmtpClient instances that all wrap the same SMTP server. Using a single instance may resolve the issue.
UPDATE
Per MSDN:
After calling SendAsync, you must wait for the e-mail transmission to complete before attempting to send another e-mail message using Send or SendAsync.
http://msdn.microsoft.com/en-us/library/x5x13z6h.aspx
So given your situation, there is almost no benefit to using SendAsync over Send. Your loop is probably stomping on something since you do not wait for the previous SendAsync to complete.
Here are a few thoughts:
SendAsync will perform almost the same as Send if you are sending a bunch of emails. Just use Send.
If you need parallel sending, use a Producer/Consumer pattern. One (or more) producing threads dump stuff into a queue to send, and multiple consuming threads each use one SmtpClient to send messages. This pattern is amazingly simple to implement with a BlockingCollection. See the example in MSDN http://msdn.microsoft.com/en-us/library/dd267312.aspx
If you use enough threads, your SMTP server will be the bottleneck. Be aware of when you are overloading it.

Related

Protocol buffers, C# and NetworkStream: messages are never received

I'm trying to use ProtocolBuffers over a NetworkStream but the messages are never fully received.
Here is my server:
var listener = new TcpListener(System.Net.IPAddress.Any, 4989);
listener.Start();
while (true)
{
var client = listener.AcceptTcpClient();
Task.Factory.StartNew(() =>
{
var message = ServerMessage.Parser.ParseFrom(client.GetStream());
Console.WriteLine(message);
});
}
Here is my client:
Thread.Sleep(2000);//Wait for server to start
var client = new TcpClient();
client.Connect("localhost", 4989);
while (true)
{
var message = new ServerMessage
{
Time = (ulong)DateTime.UtcNow.Ticks,
Type = MessageType.Content
};
message.WriteTo(client.GetStream());
Thread.Sleep(1000);
}
A full repro solution is available here: https://github.com/IanPNewson/ProtobufNetworkStreamIssue
What's going wrong?
protobuf is not a terminated protocol, by which I mean: there is literally nothing that says when an individual message ends. Because of this, by default: APIs like ParseFrom read until the end of the stream, and in an open Socket/NetworkStream: that would only happen if you sent a single message and then closed the outbound connection (not having any more bytes at the moment is not sufficient - it would need to see an actual EOF on the stream, which means you could only send one message per socket).
Because of this, you usually use framing with protobuf, which means: some means of denoting individual messages in an open stream. This is usually done via a length-prefix (you can't use a sentinel value to terminate, because protobuf can contain any byte value).
Some APIs include convenience methods for this (the *WithLengthPrefix APIs in protobuf-net, for example, although you can't just drop that in place here) - or you can implement it yourself manually. Alternatively, perhaps consider something like gRPC which deals with all the framing etc semantics for you, so you can concentrate on doing interesting work. I have a variant of gRPC that works on bare sockets, if you really don't want to deal with the full HTTP/2 side of gRPC.

How to tell Rabbit to that task fails in .Net Core

Let's imagine that we have Q named "NotificationQ" and have a consumer who gets a task from that Q and sends emails to customers.
Emailing process sends an email by API from mailgun. That API request does not turn 200 every time(the reason is not important). In that time I need to tell RabbitMQ that tasks fail. I know there is a feature called autoAck but if a request fails how the RabbitMQ client pack understood that a fail.
Am I manually trigger ack to say that request failed?
I using https://www.nuget.org/packages/RabbitMQ.Client/ pack to handle RabbitMQ tasks.
var channel = RabbitPrepareFactory.GetConnectionFactory();
channel.BasicQos(0, 1, false);
var notificationPack = channel.BasicGet("notification", true);
var message = System.Text.Encoding.UTF8.GetString(notificationPack.Body.ToArray());
var task = JsonConvert.DeserializeObject<ForgetPasswordEmailNotification>(message);
var isEmailSendSuccessful = SomeFakeEmailSendFunctions(task.Email);
if (!isEmailSendSuccessful)
{
//something for tell RabbitMQ that task fail and not delte that task in q
.......
}
I think this could be usefull. I would use something like a Dead Letter
https://www.rabbitmq.com/dlx.html
So everytime a message is failing for whatever reason, you push the message to that queue.
Once your messaged was recieved by your consumer and the scope of the operation finished, that message is acknowledged so that other consumers will not take a already processed message.
[Edit]
I dont't think its a good ideea to process a message from a queue and afterwards to leave it there if something happens to your BackEnd. If you implement the dead letter queue you could try to reprocess those messages at some time ( Maybe a CronJob ) or if you really don't wanna have dead letter queues you could try to implement in your Client a Retry Mechanism. Polly could work very well in your case https://github.com/App-vNext/Polly

How do I receive messages from an Artemis multicast queue in C#?

I'm up to send and receive messages over ActiveMQ Artemis with C# applications. In Anycast-mode, everything is working.
When i tried to send and receive in multicast-mode, i can send, but i don't receive any of the messages from the queue.
I tried the trick from java, set the "multicast" flag before the tcp uri, but an error message shows up that there isn't an implementation for "multicast"
private void Receiver()
{
IConnectionFactory factory = new NMSConnectionFactory("multicast:tcp://172.29.213.150:61616");
IConnection connection = factory.CreateConnection("artemis", "simetraehcapa");
connection.Start();
ISession session = connection.CreateSession(AcknowledgementMode.AutoAcknowledge);
IDestination destination = SessionUtil.GetDestination(session, "hund");
IMessageConsumer receiver = session.CreateConsumer(destination);
receiver.Listener += new MessageListener(Message_Listener);
}
Normally I would receive the messages, because I only switched from anycast to multicast, but actually I receive nothing.
If using the AcitveMQ OpenWire NMS client you don't apply that odd multicast thing you've done to the URI, that will give you an error. The client should just work if you use the Session API and not that confusing SessionUtil API that has resulted in many people running into issues.
I'd use Session.CreateTopic to get an ITopic instance and then create a consumer using that which should map over into Artemis Multicast addresses without you needing to do anything. You do of course need to be subscribed before any messages are sent as Topics don't retain messages if no consumers are around when the are sent.

Bulks Emails not reaching destination, lost in network

I am sending approximately 5000 emails to IIS smtp server Windows 2012 R2 (Server1) using aspose email client (using c#) in a loop. The emails fired queue up in smtp server queue. From that queue, they are all sent to the same destination (an oracle email filing server - Server2).
The problem is - approx 700-800 (randomly every time) emails are getting lost in transit.
Questions -
Is there any way that i can queue all the emails received on Server1 to ensure that it is receiving complete 5000 emails? Any setting, so it can receive emails but do not forward them?
Is smtp email delivery not guaranteed to the recipient? Since there is no throttling mechanism, i think i am choking the network by sending large number of emails, and then emails in lost in network. If it is so, is there a mechanism by which smtp server can be configured to process queue slowly. Send out a few and then wait and so on.
Aspose.Email also let you send the email in the form of bulks as well. Moreover, it is also dependent on server side that how much bulk email it may handle at any given time so as to avoid any bombardment of emails as well. There may be settings on server side. However, from Aspose.Email perspective, you may please consider using following sample code rather than sending via loops. You can divide big chunks of emails into small bulks and then send via Bulk email sending option provided by Aspose.Email.
SmtpClient client = new SmtpClient("mail.server.com", 25, "Username", "Password");
//Create instances of MailMessage class and Specify To, From, Subject and Message
MailMessage message1 = new MailMessage("msg1#from.com", "msg1#to.com", "Subject1", "message1, how are you?");
MailMessage message2 = new MailMessage("msg1#from.com", "msg2#to.com", "Subject2", "message2, how are you?");
MailMessage message3 = new MailMessage("msg1#from.com", "msg3#to.com", "Subject3", "message3, how are you?");
//Create an instance of MailMessageCollection class
MailMessageCollection manyMsg = new MailMessageCollection();
manyMsg.Add(message1);
manyMsg.Add(message2);
manyMsg.Add(message3);
//Use client.BulkSend function to complete the bulk send task
try
{
// Send Message using BulkSend method
client.Send(manyMsg);
Console.WriteLine("Message sent");
}
catch (Exception ex)
{
Trace.WriteLine(ex.ToString());
}

RabbitMQ C# API Event based Message Consumption

while (true)
{
BasicDeliverEventArgs e = (BasicDeliverEventArgs)Consumer.Queue.Dequeue();
IBasicProperties properties = e.BasicProperties;
byte[] body = e.Body;
Console.WriteLine("Recieved Message : " + Encoding.UTF8.GetString(body));
ch.BasicAck(e.DeliveryTag, false);
}
This is what we do when we Retrieve Message by subscription..We use While Loop because we want Consumer to listen Continously..what if i want to make this even based..that is when a new message arrives in the queue at that time only Consumer should Consume the message..or on any such similar event..
use the RabbitMQ.Client.Events.EventingBasicConsumer for a eventing consumer instead of a blocking one.
You're currently blocking on the Consumer.Queue.Dequeue(). If I understand your question correctly, you want to asynchronously consume messages.
The standard way of doing this would be to write your own IBasicConsumer (probably by subclassing DefaultBasicConsumer) and set it as the consumer for the channel.
The trouble with this is that you have to be very careful about what you do in IBasicConsumer.HandleBasicDelivery. If you use any synchronous AMQP methods, such as basic.publish, you'll get a dead-lock. If you do anything that takes a long time, you'll run into some other problems.
If you do need synchronous methods or long-running actions, what you're doing is about the right way to do it. Have a look at Subscription; it's an IBasicConsumer that consumes messages and puts them on a queue for you.
If you need any more help, a great place to ask is the rabbitmq-discuss mailing list.
I had this problem and could not find an answer so created a demonstration project to have the RabbitMQ subscription raise .Net events when a message is received. The subscription runs on its own thread leaving the UI (in mycase) free to do it thing.
I amusing call my project RabbitEar as it listens out for messages from the mighty RabbitMQ
I intend to share this with the RabbitMQ site so if they think its of value they can include a link / code in there examples.
Check it out at http://rabbitears.codeplex.com/
Thanks
Simon

Categories

Resources