// this method is called from Parallel Invoke, so multiple threads will be executing this concurrently private static void SendMailFromUser(SendMailFromUserArgs args) { var fromMu = args.User; // make sure creds are set and setup SMTP client instance for sender to use this session.. if (!(fromMu.networkCred is NetworkCredential)) { fromMu.networkCred = new NetworkCredential(fromMu.sAMAccountName, args.defaultPassword, DirectoryEntryContext.DefaultDomain); } using (var curSmtpClient = new SmtpClient(MailUsers.dblist[fromMu.exchangeDBIndex].CurrentServer, 587)) { curSmtpClient.Credentials = fromMu.networkCred; var from = new MailAddress(fromMu.smtpAddress, fromMu.displayName); var progress = args.progress; var bw = args.backgroundWorker; var dwea = args.doWorkEventArgs; var r = args.randomInstance; var mailBodyStyle = new BodyCompositionRules(); // only trace here if worker is not being cancelled. Otherwise if verbose tracing is enabled it can hang UI. if (!dwea.Cancel) { ts.TraceEvent(TraceEventType.Verbose, 0, "Starting sending mail from {0}", fromMu.displayName); } foreach (var mal in senderAssignments[fromMu]) { // check for user cancellation if (bw.CancellationPending) { if (!dwea.Cancel) { dwea.Cancel = true; } Interlocked.CompareExchange(ref progress.cancelled, 1, 0); bw.ReportProgress(0, progress); return; } // check for too many errors if (progress.consecutiveErrorsSending >= maxConsecutiveFailuresSending) { if (!dwea.Cancel) { dwea.Cancel = true; } if (Interlocked.Exchange(ref progress.cancelled, 2) == 0) { //only trace this once, if not already pending cancel ts.TraceEvent(TraceEventType.Critical, 0, "Stopping after {0} consecutive errors", maxConsecutiveFailuresSending); } bw.ReportProgress(0, progress); return; } // compose message var message = new MailMessage(from, mal[0]); if (mal.Count > 1) { for (int i = 1; i < mal.Count; i++) { message.To.Add(mal[i]); } } message.Body = getRandomBody(r, mailBodyStyle); message.Subject = getRandomSubject(r); // attachments if (r.Next(1, 101) > (100 - args.percentChanceOfAttachments)) { message.Attachments.Add(getRandomAttachment(r, mailBodyStyle)); if (r.Next(1, 101) > 50) // 50 percent chance of more than one attachment. { var attachments = r.Next(1, args.maxAttachments + 1); for (int i = 1; i < attachments; i++) // start i=1 because we already have 1 attachment { message.Attachments.Add(getRandomAttachment(r, mailBodyStyle)); } } } // send try { curSmtpClient.Send(message); Interlocked.Increment(ref progress.messagesSent); Interlocked.Exchange(ref progress.consecutiveErrorsSending, 0); } catch (Exception e) { Interlocked.Increment(ref progress.errorsSending); Interlocked.Increment(ref progress.consecutiveErrorsSending); ts.TraceEvent(TraceEventType.Error, 0, "sending message from user {0}. {1}", fromMu.displayName, e.ToString()); } finally { if (message != null) { message.Dispose(); } } bw.ReportProgress(0, progress); } Interlocked.Increment(ref progress.sendersDone); ts.TraceEvent(TraceEventType.Verbose, 0, "Finished sending from {0}", fromMu.displayName); bw.ReportProgress(0, progress); } }
public static void Mail(GenMailArgs args, object sender, DoWorkEventArgs dwea) { ts.TraceEvent(TraceEventType.Verbose, 0, "Gen.Mail started."); // set connection limit higher ServicePointManager.DefaultConnectionLimit = 100; ts.TraceEvent(TraceEventType.Information, 0, "Initializing..."); mailUsers = MailUsers.GetAllOUMailUsers(args.selectedOUPath); ts.TraceEvent(TraceEventType.Verbose, 0, "Got list of {0} users.", mailUsers.Count); // lower maxadditionalrecips if there are not enough users if (mailUsers.Count - 1 < args.maxAdditionalRecips) { args.maxAdditionalRecips = mailUsers.Count - 1; } // load and decompress word list if necessary if (words == null) { LoadDictionary(); } ts.TraceEvent(TraceEventType.Information, 0, "Preparing recipient lists..."); var progress = new GenMailProgress(); var bw = sender as BackgroundWorker; mailCounter = 0; // clear dictionaries in case process was interrupted senderAssignments.Clear(); mailsRemainingForRecipient.Clear(); // random instance to generate seeds for other random instances var rs = new Random(); // populate mails remaining dictionary foreach (GenMailUser mu in mailUsers) { if (bw.CancellationPending == true) { dwea.Cancel = true; return; } mailsRemainingForRecipient.Add(mu.smtpAddress, args.InitialItems); } foreach (GenMailUser mu in mailUsers) { var to = new MailAddress(mu.smtpAddress, mu.displayName); while (mailsRemainingForRecipient[mu.smtpAddress] > 0) { if (bw.CancellationPending == true) { dwea.Cancel = true; return; } // keep track of # of emails to send for accurate progress later... mailCounter++; // get random user for from address GenMailUser rmu; do { rmu = mailUsers[rs.Next(mailUsers.Count)]; }while (rmu == mu && mailUsers.Count > 1); var recipList = new List <MailAddress>() { to }; // decrement mail count mailsRemainingForRecipient[mu.smtpAddress]--; // optionally add some random recipients if there are enough people in the mailusers list if (args.maxAdditionalRecips > 0 && rs.Next(1, 101) > (100 - args.percentChanceOfExtraRecips)) { // add 1 - configured max var extraRecips = rs.Next(1, args.maxAdditionalRecips + 1); // keep track of additional recips that we don't allow dupes var genMailRecips = new List <GenMailUser>(); for (int i = 0; i < extraRecips; i++) { GenMailUser recip; do { recip = mailUsers[rs.Next(mailUsers.Count)]; }while (recip == mu || genMailRecips.Contains(recip)); // don't want duplicates if (mailsRemainingForRecipient[recip.smtpAddress] > 0) { recipList.Add(new MailAddress(recip.smtpAddress, recip.displayName)); mailsRemainingForRecipient[recip.smtpAddress]--; genMailRecips.Add(recip); } } } if (senderAssignments.ContainsKey(rmu)) { senderAssignments[rmu].Add(recipList); } else { var assignments = new List <List <MailAddress> >(); assignments.Add(recipList); senderAssignments.Add(rmu, assignments); } } } // free up memory mailsRemainingForRecipient.Clear(); var tasks = senderAssignments.Count; progress.numberOfSenders = tasks; progress.numberOfMailboxes = mailUsers.Count; progress.numberOfMailsToSend = mailCounter; var actions = new Action[tasks]; int actionIndex = 0; foreach (var senderGenMailUser in senderAssignments.Keys) { if (bw.CancellationPending == true) { dwea.Cancel = true; return; } var smfua = new SendMailFromUserArgs(); smfua.backgroundWorker = bw; smfua.doWorkEventArgs = dwea; smfua.progress = progress; smfua.User = senderGenMailUser; smfua.randomInstance = new Random(rs.Next()); smfua.defaultPassword = args.DefaultPassword; smfua.percentChanceOfAttachments = args.percentChanceOfAttachments; smfua.maxAttachments = args.maxAttachments; actions[actionIndex] = () => { SendMailFromUser(smfua); }; actionIndex++; } ts.TraceEvent(TraceEventType.Information, 0, "Starting send mail threads..."); if (mailCounter < args.InitialItems * mailUsers.Count) { ts.TraceEvent(TraceEventType.Information, 0, "Since some items will be received by multiple mailboxes,\n {0:N0} items per mailbox can be achieved by sending {1:N0} item(s) total.", args.InitialItems, mailCounter); } var opts = new ParallelOptions(); //sanity check thread count if (args.Threads > 0 && args.Threads <= 100) { opts.MaxDegreeOfParallelism = args.Threads; } else { opts.MaxDegreeOfParallelism = 3; } // invoke threads. This blocks until all complte Parallel.Invoke(opts, actions); // clear sender assignments senderAssignments.Clear(); if (dwea.Cancel) { if (progress.cancelled == 2) { ts.TraceEvent(TraceEventType.Information, 0, "Mailbox population cancelled due to too many consecutive errors."); } if (progress.cancelled == 1) { ts.TraceEvent(TraceEventType.Information, 0, "Mailbox population cancelled by user."); } } else { ts.TraceEvent(TraceEventType.Information, 0, "Done sending mail."); if (mailCounter < args.InitialItems * mailUsers.Count) { ts.TraceEvent(TraceEventType.Information, 0, "Some messages were sent to multiple mailboxes.\n Sent {0:N0} item(s) total in order for each mailbox to receive {1:N0} item(s).", mailCounter, args.InitialItems); } } }