public function process(MassMailQueue $entry, $batchSize = 100) { $this->debugOut->writeln('-----------------------------------'); $this->debugOut->writeln("Starting entry: " . $entry->getSubject()); $start = $entry->getPosition(); // Don't change (reduce) our original total after the first time it's // set as that could cause us to not send to the complete list of users // we originally found with our filter $total = max($this->countUsers($entry), $entry->getTotal()); $this->debugOut->writeln("Found total: {$total}"); if (!$this->simulate) { $entry->setTotal($total); $entry->setStatus(MassMailQueue::STATUS_PROCESSING); $this->em->flush(); } $complete = false; // loop through, constantly fetching from the last user + 1, until nothing left. // LIMIT x,y would be slow (needs to look at *all* results even before offset), // and prone to duplicate/missing sends if a user changes their preferences mid-process. while (true) { $currentDate = new \DateTime(); $userLimit = $batchSize; // if not a preview, apply batch limiting if ($entry->getType() !== MassMailQueue::TYPE_PREVIEW) { $remaining = $this->limiter->getMessagesRemaining($currentDate); if ($remaining <= 0) { $this->debugOut->writeln('Reached batch limitations, breaking'); break; } $userLimit = min($userLimit, $remaining); } // allow pausing $this->em->refresh($entry); if ($entry->getStatus() === MassMailQueue::STATUS_PAUSED) { $this->debugOut->writeln('Entry paused, breaking'); break; } $users = $this->fetchUsers($entry, $start, $userLimit); if (empty($users)) { $this->debugOut->writeln('No more users found, breaking loop'); // Make sure we're not here because we're over our limit if ($remaining > 0) { $complete = true; } break; } foreach ($users as $user) { $this->debugOut->writeln("User #{$user['id']}; un={$user['username']}; em={$user['email']}; " . "fn={$user['properties']['FirstName']} {$user['properties']['LastName']}"); if (!$this->simulate) { $html = $this->renderTemplate($entry, $user); $message = \Swift_Message::newInstance($entry->getSubject(), $html, 'text/html', 'utf-8'); $message->setFrom('*****@*****.**'); try { $message->setTo($user['email']); } catch (\Swift_RfcComplianceException $e) { // Just skip over bad e-mail addresses $this->debugOut->writeln("Skipping badly formatted e-mail address: {$user['email']}"); continue; } $headers = $message->getHeaders(); $headers->addTextHeader('X-Gc-Type', 'mass'); $unsub = $this->getUnsubscribeLink($entry, $user); if ($unsub) { $headers->addTextHeader('List-Unsubscribe', '<' . $this->getUnsubscribeLink($entry, $user) . '>'); } $this->mailer->send($message); } $start = $user['id'] + 1; } if (!$this->simulate) { $entry->setPosition($start); $entry->setSent($entry->getSent() + count($users)); $this->em->flush(); } if ($entry->getType() === MassMailQueue::TYPE_PREVIEW) { $complete = true; break; } else { $this->limiter->addMessagesSent($currentDate, count($users)); } } if (!$this->simulate) { if ($complete) { // This is more accurate than the reverse, I think. $entry->setTotal($entry->getSent()); $entry->setStatus(MassMailQueue::STATUS_COMPLETE); } $this->em->flush(); } }