/** * Get the content hash to note if the content has been changed * * @return string */ public function getContentHash() { if (null !== $this->helper) { return $this->helper->getContentHash(); } else { return md5($this->getContent() . $this->getPlainText()); } }
/** * Returns MailHelper wrapper for Swift_Message via $helper->message * * @param bool $cleanSlate False to preserve current settings, i.e. to process batched emails * * @return MailHelper */ public function getMailer($cleanSlate = true) { if ($this->mailHelper == null) { $this->mailHelper = new MailHelper($this, $this->container->get('mailer'), array($this->getParameter('mailer_from_email') => $this->getParameter('mailer_from_name'))); } else { $this->mailHelper->reset($cleanSlate); } return $this->mailHelper; }
public function indexAction($idHash) { /** @var \Mautic\EmailBundle\Model\EmailModel $model */ $model = $this->factory->getModel('email'); $stat = $model->getEmailStatus($idHash); if (!empty($stat)) { $entity = $stat->getEmail(); $model->hitEmail($stat, $this->request, true); // Check for stored copy $content = $stat->getCopy(); if (!empty($content)) { // Copy stored in stats $tokens = $stat->getTokens(); if (!empty($tokens)) { // Override tracking_pixel so as to not cause a double hit $tokens['{tracking_pixel}'] = MailHelper::getBlankPixel(); $content = str_ireplace(array_keys($tokens), $tokens, $content); } } else { // Old way where stats didn't store content //the lead needs to have fields populated $statLead = $stat->getLead(); $lead = $this->factory->getModel('lead')->getLead($statLead->getId()); $template = $entity->getTemplate(); if (!empty($template)) { $slots = $this->factory->getTheme($template)->getSlots('email'); $response = $this->render('MauticEmailBundle::public.html.php', array('inBrowser' => true, 'slots' => $slots, 'content' => $entity->getContent(), 'email' => $entity, 'lead' => $lead, 'template' => $template)); //replace tokens $content = $response->getContent(); } else { $content = $entity->getCustomHtml(); } $content = EmojiHelper::toEmoji($content, 'short'); $tokens = $stat->getTokens(); // Override tracking_pixel so as to not cause a double hit $tokens['{tracking_pixel}'] = MailHelper::getBlankPixel(); $event = new EmailSendEvent(null, array('content' => $content, 'lead' => $lead, 'email' => $entity, 'idHash' => $idHash, 'tokens' => $tokens)); $this->factory->getDispatcher()->dispatch(EmailEvents::EMAIL_ON_DISPLAY, $event); $content = $event->getContent(true); } $analytics = htmlspecialchars_decode($this->factory->getParameter('google_analytics', '')); // Check for html doc if (strpos($content, '<html>') === false) { $content = "<html>\n<head>{$analytics}</head>\n<body>{$content}</body>\n</html>"; } elseif (strpos($content, '<head>') === false) { $content = str_replace('<html>', "<html>\n<head>\n{$analytics}\n</head>", $content); } elseif (!empty($analytics)) { $content = str_replace('</head>', $analytics . "\n</head>", $content); } return new Response($content); } $this->notFound(); }
/** * Creates Hubspot lead. * * @param array $data * * @return mixed */ public function createLead(array $data) { /* * As Hubspot integration requires a valid email * If the email is not valid we don't proceed with the request */ $email = $data['email']; //Check if the is a valid email MailHelper::validateEmail($email); //Format data for request $formattedLeadData = $this->integration->formatLeadDataForCreateOrUpdate($data); return $this->request('v1/contact/createOrUpdate/email/' . $email, $formattedLeadData, 'POST'); }
public function indexAction($idHash) { /** @var \Mautic\EmailBundle\Model\EmailModel $model */ $model = $this->getModel('email'); $stat = $model->getEmailStatus($idHash); if (!empty($stat)) { if ($this->get('mautic.security')->isAnonymous()) { $model->hitEmail($stat, $this->request, true); } $tokens = $stat->getTokens(); if (is_array($tokens)) { // Override tracking_pixel so as to not cause a double hit $tokens['{tracking_pixel}'] = MailHelper::getBlankPixel(); } if ($copy = $stat->getStoredCopy()) { $subject = $copy->getSubject(); $content = $copy->getBody(); // Convert emoji $content = EmojiHelper::toEmoji($content, 'short'); $subject = EmojiHelper::toEmoji($subject, 'short'); // Replace tokens if (!empty($tokens)) { $content = str_ireplace(array_keys($tokens), $tokens, $content); $subject = str_ireplace(array_keys($tokens), $tokens, $subject); } } else { $subject = ''; $content = ''; } // Add analytics $analytics = $this->factory->getHelper('template.analytics')->getCode(); // Check for html doc if (strpos($content, '<html>') === false) { $content = "<html>\n<head>{$analytics}</head>\n<body>{$content}</body>\n</html>"; } elseif (strpos($content, '<head>') === false) { $content = str_replace('<html>', "<html>\n<head>\n{$analytics}\n</head>", $content); } elseif (!empty($analytics)) { $content = str_replace('</head>', $analytics . "\n</head>", $content); } // Add subject as title if (!empty($subject)) { if (strpos($content, '<title></title>') !== false) { $content = str_replace('<title></title>', "<title>{$subject}</title>", $content); } elseif (strpos($content, '<title>') === false) { $content = str_replace('<head>', "<head>\n<title>{$subject}</title>", $content); } } return new Response($content); } $this->notFound(); }
/** * @param User $user */ public function sendResetEmail(User $user) { $mailer = $this->mailHelper->getMailer(); $resetToken = $this->getResetToken($user); $resetLink = $this->router->generate('mautic_user_passwordresetconfirm', ['token' => $resetToken], true); $mailer->setTo([$user->getEmail() => $user->getName()]); $mailer->setSubject($this->translator->trans('mautic.user.user.passwordreset.subject')); $text = $this->translator->trans('mautic.user.user.passwordreset.email.body', ['%name%' => $user->getFirstName(), '%resetlink%' => '<a href="' . $resetLink . '">' . $resetLink . '</a>']); $text = str_replace('\\n', "\n", $text); $html = nl2br($text); $mailer->setBody($html); $mailer->setPlainText(strip_tags($text)); $mailer->send(); }
/** * @param Events\SubmissionEvent $event */ public function onFormSubmitActionRepost(Events\SubmissionEvent $event) { if (!$event->checkContext('form.repost')) { return; } $post = $event->getPost(); $results = $event->getResults(); $config = $event->getActionConfig(); $fields = $event->getFields(); $lead = $event->getSubmission()->getLead(); $matchedFields = []; $payload = ['mautic_contact' => $lead->getProfileFields(), 'mautic_form' => ['id' => $post['formId'], 'name' => $post['formName'], 'url' => $post['return']]]; $fieldTypes = []; foreach ($fields as $field) { $fieldTypes[$field['alias']] = $field['type']; if (!isset($post[$field['alias']]) || 'button' == $field['type']) { continue; } $key = !empty($config[$field['alias']]) ? $config[$field['alias']] : $field['alias']; // Use the cleaned value by default - but if set to not save result, get from post $value = isset($results[$field['alias']]) ? $results[$field['alias']] : $post[$field['alias']]; $matchedFields[$key] = $field['alias']; $payload[$key] = $value; } $headers = ['X-Forwarded-For' => $event->getSubmission()->getIpAddress()->getIpAddress()]; if (!empty($config['authorization_header'])) { if (strpos($config['authorization_header'], ':') !== false) { list($key, $value) = explode(':', $config['authorization_header']); } else { $key = 'Authorization'; $value = $config['authorization_header']; } $headers[trim($key)] = trim($value); } try { $client = new Client(['timeout' => 15]); $response = $client->post($config['post_url'], ['form_params' => $payload, 'headers' => $headers]); if ($redirect = $this->parseResponse($response, $matchedFields)) { $event->setPostSubmitCallbackResponse('form.repost', new RedirectResponse($redirect)); } } catch (ServerException $exception) { $this->parseResponse($exception->getResponse(), $matchedFields); } catch (\Exception $exception) { if ($exception instanceof ValidationException) { if ($violations = $exception->getViolations()) { throw $exception; } } $email = $config['failure_email']; // Failed so send email if applicable if (!empty($email)) { // Remove Mautic values and password fields foreach ($post as $key => $value) { if (in_array($key, ['messenger', 'submit', 'formId', 'formid', 'formName', 'return'])) { unset($post[$key]); } if (isset($fieldTypes[$key]) && in_array($fieldTypes[$key], ['password'])) { $post[$key] = '*********'; } } $post['mautic_contact'] = array_filter($payload['mautic_contact']); $post['mautic_form'] = $payload['mautic_form']; $results = $this->postToHtml($post); $submission = $event->getSubmission(); $emails = $emails = $this->getEmailsFromString($email); $this->mailer->setTo($emails); $this->mailer->setSubject($this->translator->trans('mautic.form.action.repost.failed_subject', ['%form%' => $submission->getForm()->getName()])); $this->mailer->setBody($this->translator->trans('mautic.form.action.repost.failed_message', ['%link%' => $this->router->generate('mautic_form_results', ['objectId' => $submission->getForm()->getId(), 'result' => $submission->getId()], UrlGeneratorInterface::ABSOLUTE_URL), '%message%' => $exception->getMessage(), '%results%' => $results])); $this->mailer->parsePlainText(); $this->mailer->send(); } } }
/** * {@inheritdoc} */ protected function getPayload() { $metadata = $this->getMetadata(); $mauticTokens = $mandrillMergeVars = $mandrillMergePlaceholders = array(); // Mandrill uses *|PLACEHOLDER|* for tokens so Mautic's need to be replaced if (!empty($metadata)) { $metadataSet = reset($metadata); $tokens = !empty($metadataSet['tokens']) ? $metadataSet['tokens'] : array(); $mauticTokens = array_keys($tokens); $mandrillMergeVars = $mandrillMergePlaceholders = array(); foreach ($mauticTokens as $token) { $mandrillMergeVars[$token] = strtoupper(preg_replace("/[^a-z0-9]+/i", "", $token)); $mandrillMergePlaceholders[$token] = '*|' . $mandrillMergeVars[$token] . '|*'; } } $message = $this->messageToArray($mauticTokens, $mandrillMergePlaceholders, true); // Not used ATM unset($message['headers']); $message['from_email'] = $message['from']['email']; $message['from_name'] = $message['from']['name']; unset($message['from']); if (!empty($metadata)) { // Mandrill will only send a single email to cc and bcc of the first set of tokens // so we have to manually set them as to addresses // Problem is that it's not easy to know what email is sent so will tack it at the top $insertCcEmailHeader = true; $message['html'] = '*|HTMLCCEMAILHEADER|*' . $message['html']; if (!empty($message['text'])) { $message['text'] = '*|TEXTCCEMAILHEADER|*' . $message['text']; } // Do not expose all the emails in the if using metadata $message['preserve_recipients'] = false; $bcc = $message['recipients']['bcc']; $cc = $message['recipients']['cc']; // Unset the cc and bcc as they will need to be sent as To with each set of tokens unset($message['recipients']['bcc'], $message['recipients']['cc']); } // Generate the recipients $recipients = $rcptMergeVars = $rcptMetadata = array(); $translator = $this->factory->getTranslator(); foreach ($message['recipients'] as $type => $typeRecipients) { foreach ($typeRecipients as $rcpt) { $rcpt['type'] = $type; $recipients[] = $rcpt; if ($type == 'to' && isset($metadata[$rcpt['email']])) { if (!empty($metadata[$rcpt['email']]['tokens'])) { $mergeVars = array('rcpt' => $rcpt['email'], 'vars' => array()); // This must not be included for CC and BCCs $trackingPixelToken = array(); foreach ($metadata[$rcpt['email']]['tokens'] as $token => $value) { if ($token == '{tracking_pixel}') { $trackingPixelToken = array(array('name' => $mandrillMergeVars[$token], 'content' => $value)); continue; } $mergeVars['vars'][] = array('name' => $mandrillMergeVars[$token], 'content' => $value); } if (!empty($insertCcEmailHeader)) { // Make a copy before inserted the blank tokens $ccMergeVars = $mergeVars; $mergeVars['vars'] = array_merge($mergeVars['vars'], $trackingPixelToken, array(array('name' => 'HTMLCCEMAILHEADER', 'content' => ''), array('name' => 'TEXTCCEMAILHEADER', 'content' => ''))); } else { // Just merge the tracking pixel tokens $mergeVars['vars'] = array_merge($mergeVars['vars'], $trackingPixelToken); } // Add the vars $rcptMergeVars[] = $mergeVars; // Special handling of CC and BCC with tokens if (!empty($cc) || !empty($bcc)) { $ccMergeVars['vars'] = array_merge($ccMergeVars['vars'], array(array('name' => 'HTMLCCEMAILHEADER', 'content' => $translator->trans('mautic.core.email.cc.copy', array('%email%' => $rcpt['email'])) . "<br /><br />"), array('name' => 'TEXTCCEMAILHEADER', 'content' => $translator->trans('mautic.core.email.cc.copy', array('%email%' => $rcpt['email'])) . "\n\n"), array('name' => 'TRACKINGPIXEL', 'content' => MailHelper::getBlankPixel()))); // If CC and BCC, remove the ct from URLs to prevent false lead tracking foreach ($ccMergeVars['vars'] as &$var) { if (strpos($var['content'], 'http') !== false && ($ctPos = strpos($var['content'], 'ct=') !== false)) { // URL so make sure a ct query is not part of it $var['content'] = substr($var['content'], 0, $ctPos); } } // Send same tokens to each CC if (!empty($cc)) { foreach ($cc as $ccRcpt) { $recipients[] = $ccRcpt; $ccMergeVars['rcpt'] = $ccRcpt['email']; $rcptMergeVars[] = $ccMergeVars; } } // And same to BCC if (!empty($bcc)) { foreach ($bcc as $ccRcpt) { $recipients[] = $ccRcpt; $ccMergeVars['rcpt'] = $ccRcpt['email']; $rcptMergeVars[] = $ccMergeVars; } } } unset($ccMergeVars, $mergeVars, $metadata[$rcpt['email']]['tokens']); } if (!empty($metadata[$rcpt['email']])) { $rcptMetadata[] = array('rcpt' => $rcpt['email'], 'values' => $metadata[$rcpt['email']]); unset($metadata[$rcpt['email']]); } } } } $message['to'] = $recipients; unset($message['recipients']); // Set the merge vars $message['merge_vars'] = $rcptMergeVars; // Set the rest of $metadata as recipient_metadata $message['recipient_metadata'] = $rcptMetadata; // Set the reply to if (!empty($message['replyTo'])) { $message['headers']['Reply-To'] = $message['replyTo']['email']; } unset($message['replyTo']); // Package it up $payload = json_encode(array('key' => $this->getPassword(), 'message' => $message)); return $payload; }
/** * Converts \Swift_Message into associative array. * * @param array $search If the mailer requires tokens in another format than Mautic's, pass array of Mautic tokens to replace * @param array $replace If the mailer requires tokens in another format than Mautic's, pass array of replacement tokens * @param bool|false $binaryAttachments True to convert file attachments to binary * * @return array|\Swift_Message */ protected function messageToArray($search = [], $replace = [], $binaryAttachments = false) { if (!empty($search)) { MailHelper::searchReplaceTokens($search, $replace, $this->message); } $from = $this->message->getFrom(); $fromEmail = current(array_keys($from)); $fromName = $from[$fromEmail]; $message = ['html' => $this->message->getBody(), 'text' => MailHelper::getPlainTextFromMessage($this->message), 'subject' => $this->message->getSubject(), 'from' => ['name' => $fromName, 'email' => $fromEmail]]; // Generate the recipients $message['recipients'] = ['to' => [], 'cc' => [], 'bcc' => []]; $to = $this->message->getTo(); foreach ($to as $email => $name) { $message['recipients']['to'][$email] = ['email' => $email, 'name' => $name]; } $cc = $this->message->getCc(); if (!empty($cc)) { foreach ($cc as $email => $name) { $message['recipients']['cc'][$email] = ['email' => $email, 'name' => $name]; } } $bcc = $this->message->getBcc(); if (!empty($bcc)) { foreach ($bcc as $email => $name) { $message['recipients']['bcc'][$email] = ['email' => $email, 'name' => $name]; } } $replyTo = $this->message->getReplyTo(); if (!empty($replyTo)) { foreach ($replyTo as $email => $name) { $message['replyTo'] = ['email' => $email, 'name' => $name]; } } $returnPath = $this->message->getReturnPath(); if (!empty($returnPath)) { $message['returnPath'] = $returnPath; } // Attachments $children = $this->message->getChildren(); $attachments = []; foreach ($children as $child) { if ($child instanceof \Swift_Attachment) { $attachments[] = ['type' => $child->getContentType(), 'name' => $child->getFilename(), 'content' => $child->getEncoder()->encodeString($child->getBody())]; } } if ($binaryAttachments) { // Convert attachments to binary if applicable $message['attachments'] = $attachments; $fileAttachments = $this->getAttachments(); if (!empty($fileAttachments)) { foreach ($fileAttachments as $attachment) { if (file_exists($attachment['filePath']) && is_readable($attachment['filePath'])) { try { $swiftAttachment = \Swift_Attachment::fromPath($attachment['filePath']); if (!empty($attachment['fileName'])) { $swiftAttachment->setFilename($attachment['fileName']); } if (!empty($attachment['contentType'])) { $swiftAttachment->setContentType($attachment['contentType']); } if (!empty($attachment['inline'])) { $swiftAttachment->setDisposition('inline'); } $message['attachments'][] = ['type' => $swiftAttachment->getContentType(), 'name' => $swiftAttachment->getFilename(), 'content' => $swiftAttachment->getEncoder()->encodeString($swiftAttachment->getBody())]; } catch (\Exception $e) { error_log($e); } } } } } else { $message['binary_attachments'] = $attachments; $message['file_attachments'] = $this->getAttachments(); } $message['headers'] = []; $headers = $this->message->getHeaders()->getAll(); /** @var \Swift_Mime_Header $header */ foreach ($headers as $header) { if ($header->getFieldType() == \Swift_Mime_Header::TYPE_TEXT) { $message['headers'][$header->getFieldName()] = $header->getFieldBodyModel(); } } return $message; }
/** * Send an email to lead(s) * * @param $email * @param $users * @param mixed $lead * @param array $tokens * @param array $assetAttachments * @param bool $saveStat * * @return mixed * @throws \Doctrine\ORM\ORMException */ public function sendEmailToUser($email, $users, $lead = null, $tokens = [], $assetAttachments = [], $saveStat = true) { if (!($emailId = $email->getId())) { return false; } if (!is_array($users)) { $user = ['id' => $users]; $users = [$user]; } //get email settings $emailSettings =& $this->getEmailSettings($email, false); //noone to send to so bail if (empty($users)) { return false; } $mailer = $this->mailHelper->getMailer(); $mailer->setLead($lead, true); $mailer->setTokens($tokens); $mailer->setEmail($email, false, $emailSettings[$emailId]['slots'], $assetAttachments, !$saveStat); $errors = []; foreach ($users as $user) { $idHash = uniqid(); $mailer->setIdHash($idHash); if (!is_array($user)) { $id = $user; $user = ['id' => $id]; } else { $id = $user['id']; } if (!isset($user['email'])) { $userEntity = $this->userModel->getEntity($id); $user['email'] = $userEntity->getEmail(); $user['firstname'] = $userEntity->getFirstName(); $user['lastname'] = $userEntity->getLastName(); } if (!$mailer->setTo($user['email'], $user['firstname'] . ' ' . $user['lastname'])) { $errors[] = "{$user['email']}: " . $this->translator->trans('mautic.email.bounce.reason.bad_email'); } else { if (!$mailer->queue(true)) { $errorArray = $mailer->getErrors(); unset($errorArray['failures']); $errors[] = "{$user['email']}: " . implode('; ', $errorArray); } if ($saveStat) { $saveEntities[] = $mailer->createEmailStat(false, $user['email']); } } } //flush the message if (!$mailer->flushQueue()) { $errorArray = $mailer->getErrors(); unset($errorArray['failures']); $errors[] = implode('; ', $errorArray); } if (isset($saveEntities)) { $this->getStatRepository()->saveEntities($saveEntities); } //save some memory unset($mailer); return $errors; }
/** * @param $fields * @param $data * @param null $owner * @param null $list * @param null $tags * @param bool $persist Persist to the database; otherwise return entity * * @return bool * @throws \Doctrine\ORM\ORMException * @throws \Swift_RfcComplianceException */ public function importLead($fields, $data, $owner = null, $list = null, $tags = null, $persist = true) { // Let's check for an existing lead by email $hasEmail = !empty($fields['email']) && !empty($data[$fields['email']]); if ($hasEmail) { // Validate the email MailHelper::validateEmail($data[$fields['email']]); $leadFound = $this->getRepository()->getLeadByEmail($data[$fields['email']]); $lead = $leadFound ? $this->em->getReference('MauticLeadBundle:Lead', $leadFound['id']) : new Lead(); $merged = $leadFound; } else { $lead = new Lead(); $merged = false; } if (!empty($fields['dateAdded']) && !empty($data[$fields['dateAdded']])) { $dateAdded = new DateTimeHelper($data[$fields['dateAdded']]); $lead->setDateAdded($dateAdded->getUtcDateTime()); } unset($fields['dateAdded']); if (!empty($fields['dateModified']) && !empty($data[$fields['dateModified']])) { $dateModified = new DateTimeHelper($data[$fields['dateModified']]); $lead->setDateModified($dateModified->getUtcDateTime()); } unset($fields['dateModified']); if (!empty($fields['lastActive']) && !empty($data[$fields['lastActive']])) { $lastActive = new DateTimeHelper($data[$fields['lastActive']]); $lead->setLastActive($lastActive->getUtcDateTime()); } unset($fields['lastActive']); if (!empty($fields['dateIdentified']) && !empty($data[$fields['dateIdentified']])) { $dateIdentified = new DateTimeHelper($data[$fields['dateIdentified']]); $lead->setDateIdentified($dateIdentified->getUtcDateTime()); } unset($fields['dateIdentified']); if (!empty($fields['createdByUser']) && !empty($data[$fields['createdByUser']])) { $userRepo = $this->em->getRepository('MauticUserBundle:User'); $createdByUser = $userRepo->findByIdentifier($data[$fields['createdByUser']]); if ($createdByUser !== null) { $lead->setCreatedBy($createdByUser); } } unset($fields['createdByUser']); if (!empty($fields['modifiedByUser']) && !empty($data[$fields['modifiedByUser']])) { $userRepo = $this->em->getRepository('MauticUserBundle:User'); $modifiedByUser = $userRepo->findByIdentifier($data[$fields['modifiedByUser']]); if ($modifiedByUser !== null) { $lead->setModifiedBy($modifiedByUser); } } unset($fields['modifiedByUser']); if (!empty($fields['ip']) && !empty($data[$fields['ip']])) { $addresses = explode(',', $data[$fields['ip']]); foreach ($addresses as $address) { $ipAddress = new IpAddress(); $ipAddress->setIpAddress(trim($address)); $lead->addIpAddress($ipAddress); } } unset($fields['ip']); if (!empty($fields['points']) && !empty($data[$fields['points']]) && $lead->getId() === null) { // Add points only for new leads $lead->setPoints($data[$fields['points']]); //add a lead point change log $log = new PointsChangeLog(); $log->setDelta($data[$fields['points']]); $log->setLead($lead); $log->setType('lead'); $log->setEventName($this->factory->getTranslator()->trans('mautic.lead.import.event.name')); $log->setActionName($this->factory->getTranslator()->trans('mautic.lead.import.action.name', array('%name%' => $this->factory->getUser()->getUsername()))); $log->setIpAddress($this->factory->getIpAddress()); $log->setDateAdded(new \DateTime()); $lead->addPointsChangeLog($log); } unset($fields['points']); // Set unsubscribe status if (!empty($fields['doNotEmail']) && !empty($data[$fields['doNotEmail']]) && $hasEmail) { $doNotEmail = filter_var($data[$fields['doNotEmail']], FILTER_VALIDATE_BOOLEAN); if ($doNotEmail) { $reason = $this->factory->getTranslator()->trans('mautic.lead.import.by.user', array("%user%" => $this->factory->getUser()->getUsername())); // The email must be set for successful unsubscribtion $lead->addUpdatedField('email', $data[$fields['email']]); $this->unsubscribeLead($lead, $reason, false); } } unset($fields['doNotEmail']); if ($owner !== null) { $lead->setOwner($this->em->getReference('MauticUserBundle:User', $owner)); } if ($tags !== null) { $this->modifyTags($lead, $tags, null, false); } // Set profile data foreach ($fields as $leadField => $importField) { // Prevent overwriting existing data with empty data if (array_key_exists($importField, $data) && !is_null($data[$importField]) && $data[$importField] != '') { $lead->addUpdatedField($leadField, $data[$importField]); } } $lead->imported = true; if ($persist) { $this->saveEntity($lead); if ($list !== null) { $this->addToLists($lead, array($list)); } } return $merged; }
/** * @return array */ public function getTextHeaders() { return $this->helper !== null ? $this->helper->getCustomHeaders() : $this->headers; }
/** * @param $fields * @param $data * @param null $owner * @param null $list * @param null $tags * @param bool $persist Persist to the database; otherwise return entity * * @return bool * @throws \Doctrine\ORM\ORMException * @throws \Swift_RfcComplianceException */ public function importLead($fields, $data, $owner = null, $list = null, $tags = null, $persist = true) { // Let's check for an existing lead by email $hasEmail = !empty($fields['email']) && !empty($data[$fields['email']]); if ($hasEmail) { // Validate the email MailHelper::validateEmail($data[$fields['email']]); $leadFound = $this->getRepository()->getLeadByEmail($data[$fields['email']]); $lead = $leadFound ? $this->em->getReference('MauticLeadBundle:Lead', $leadFound['id']) : new Lead(); $merged = $leadFound; } else { $lead = new Lead(); $merged = false; } if (!empty($fields['dateAdded']) && !empty($data[$fields['dateAdded']])) { $dateAdded = new DateTimeHelper($data[$fields['dateAdded']]); $lead->setDateAdded($dateAdded->getUtcDateTime()); } unset($fields['dateAdded']); if (!empty($fields['dateModified']) && !empty($data[$fields['dateModified']])) { $dateModified = new DateTimeHelper($data[$fields['dateModified']]); $lead->setDateModified($dateModified->getUtcDateTime()); } unset($fields['dateModified']); if (!empty($fields['lastActive']) && !empty($data[$fields['lastActive']])) { $lastActive = new DateTimeHelper($data[$fields['lastActive']]); $lead->setLastActive($lastActive->getUtcDateTime()); } unset($fields['lastActive']); if (!empty($fields['dateIdentified']) && !empty($data[$fields['dateIdentified']])) { $dateIdentified = new DateTimeHelper($data[$fields['dateIdentified']]); $lead->setDateIdentified($dateIdentified->getUtcDateTime()); } unset($fields['dateIdentified']); if (!empty($fields['createdByUser']) && !empty($data[$fields['createdByUser']])) { $userRepo = $this->em->getRepository('MauticUserBundle:User'); $createdByUser = $userRepo->findByIdentifier($data[$fields['createdByUser']]); if ($createdByUser !== null) { $lead->setCreatedBy($createdByUser); } } unset($fields['createdByUser']); if (!empty($fields['modifiedByUser']) && !empty($data[$fields['modifiedByUser']])) { $userRepo = $this->em->getRepository('MauticUserBundle:User'); $modifiedByUser = $userRepo->findByIdentifier($data[$fields['modifiedByUser']]); if ($modifiedByUser !== null) { $lead->setModifiedBy($modifiedByUser); } } unset($fields['modifiedByUser']); if (!empty($fields['ip']) && !empty($data[$fields['ip']])) { $addresses = explode(',', $data[$fields['ip']]); foreach ($addresses as $address) { $ipAddress = new IpAddress(); $ipAddress->setIpAddress(trim($address)); $lead->addIpAddress($ipAddress); } } unset($fields['ip']); if (!empty($fields['points']) && !empty($data[$fields['points']]) && $lead->getId() === null) { // Add points only for new leads $lead->setPoints($data[$fields['points']]); //add a lead point change log $log = new PointsChangeLog(); $log->setDelta($data[$fields['points']]); $log->setLead($lead); $log->setType('lead'); $log->setEventName($this->translator->trans('mautic.lead.import.event.name')); $log->setActionName($this->translator->trans('mautic.lead.import.action.name', array('%name%' => $this->user->getUsername()))); $log->setIpAddress($this->ipLookupHelper->getIpAddress()); $log->setDateAdded(new \DateTime()); $lead->addPointsChangeLog($log); } if (!empty($fields['stage']) && !empty($data[$fields['stage']])) { static $stages = []; $stageName = $data[$fields['stage']]; if (!array_key_exists($stageName, $stages)) { // Set stage for contact $stage = $this->em->getRepository('MauticStageBundle:Stage')->getStageByName($stageName); if (empty($stage)) { $stage = new Stage(); $stage->setName($stageName); $stages[$stageName] = $stage; } } else { $stage = $stages[$stageName]; } $lead->setStage($stage); //add a contact stage change log $log = new StagesChangeLog(); $log->setEventName($stage->getId() . ":" . $stage->getName()); $log->setLead($lead); $log->setActionName($this->translator->trans('mautic.lead.import.action.name', ['%name%' => $this->user->getUsername()])); $log->setDateAdded(new \DateTime()); $lead->stageChangeLog($log); } unset($fields['stage']); // Set unsubscribe status if (!empty($fields['doNotEmail']) && !empty($data[$fields['doNotEmail']]) && $hasEmail) { $doNotEmail = filter_var($data[$fields['doNotEmail']], FILTER_VALIDATE_BOOLEAN); if ($doNotEmail) { $reason = $this->translator->trans('mautic.lead.import.by.user', array("%user%" => $this->user->getUsername())); // The email must be set for successful unsubscribtion $lead->addUpdatedField('email', $data[$fields['email']]); $this->addDncForLead($lead, 'email', $reason, DoNotContact::MANUAL); } } unset($fields['doNotEmail']); if ($owner !== null) { $lead->setOwner($this->em->getReference('MauticUserBundle:User', $owner)); } if ($tags !== null) { $this->modifyTags($lead, $tags, null, false); } // Set profile data using the form so that values are validated $fieldData = []; foreach ($fields as $leadField => $importField) { // Prevent overwriting existing data with empty data if (array_key_exists($importField, $data) && !is_null($data[$importField]) && $data[$importField] != '') { $fieldData[$leadField] = $data[$importField]; } } static $leadFields; if (null === $leadFields) { $leadFields = $this->leadFieldModel->getEntities(array('force' => array(array('column' => 'f.isPublished', 'expr' => 'eq', 'value' => true)), 'hydration_mode' => 'HYDRATE_ARRAY')); } $form = $this->createForm($lead, $this->formFactory, null, ['fields' => $leadFields, 'csrf_protection' => false]); // Unset stage and owner from the form because it's already been handled unset($form['stage'], $form['owner']); $form->submit($fieldData); if (!$form->isValid()) { $fieldErrors = []; foreach ($form as $formField) { $errors = $formField->getErrors(true); if (count($errors)) { $errorString = $formField->getConfig()->getOption('label') . ": "; foreach ($errors as $error) { $errorString .= " {$error->getMessage()}"; } $fieldErrors[] = $errorString; } } $fieldErrors = implode("\n", $fieldErrors); throw new \Exception($fieldErrors); } else { // All clear foreach ($fieldData as $field => $value) { $lead->addUpdatedField($field, $value); } } $lead->imported = true; if ($persist) { $this->saveEntity($lead); if ($list !== null) { $this->addToLists($lead, array($list)); } } return $merged; }
/** * Sends the email to a specific lead * * @param int $id Email ID * @param int $leadId Lead ID * * @return \Symfony\Component\HttpFoundation\Response * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException */ public function sendLeadAction($id, $leadId) { $entity = $this->model->getEntity($id); if (null !== $entity) { if (!$this->checkEntityAccess($entity, 'view')) { return $this->accessDenied(); } $leadModel = $this->getModel('lead'); $lead = $leadModel->getEntity($leadId); if ($lead == null) { return $this->notFound(); } elseif (!$this->security->hasEntityAccess('lead:leads:viewown', 'lead:leads:viewother', $lead->getOwner())) { return $this->accessDenied(); } $post = $this->request->request->all(); $tokens = !empty($post['tokens']) ? $post['tokens'] : array(); $cleantokens = array_map(function ($v) { return InputHelper::clean($v); }, $tokens); $leadFields = array_merge(array('id' => $leadId), $leadModel->flattenFields($lead->getFields())); if (MailHelper::applyFrequencyRules($lead)) { $this->model->sendEmail($entity, $leadFields, array('source' => array('api', 0), 'tokens' => $cleantokens)); } $view = $this->view(array('success' => 1), Codes::HTTP_OK); return $this->handleView($view); } return $this->notFound(); }
public function indexAction($idHash) { /** @var \Mautic\EmailBundle\Model\EmailModel $model */ $model = $this->factory->getModel('email'); $stat = $model->getEmailStatus($idHash); if (!empty($stat)) { $emailEntity = $stat->getEmail(); if ($this->factory->getSecurity()->isAnonymous()) { $model->hitEmail($stat, $this->request, true); } $tokens = $stat->getTokens(); if (is_array($tokens)) { // Override tracking_pixel so as to not cause a double hit $tokens['{tracking_pixel}'] = MailHelper::getBlankPixel(); } // Check for stored copy $copy = $stat->getStoredCopy(); if (null === $copy) { /** * @deprecated - to be removed in 2.0 */ $subject = ''; $content = $stat->getCopy(); if (empty($content) && null !== $emailEntity) { // Old way where stats didn't store content //the lead needs to have fields populated $statLead = $stat->getLead(); $lead = $this->factory->getModel('lead')->getLead($statLead->getId()); $template = $emailEntity->getTemplate(); if (!empty($template)) { $slots = $this->factory->getTheme($template)->getSlots('email'); $assetsHelper = $this->factory->getHelper('template.assets'); $assetsHelper->addCustomDeclaration('<meta name="robots" content="noindex">'); $this->processSlots($slots, $emailEntity); $logicalName = $this->factory->getHelper('theme')->checkForTwigTemplate(':' . $template . ':email.html.php'); $response = $this->render($logicalName, array('inBrowser' => true, 'slots' => $slots, 'content' => $emailEntity->getContent(), 'email' => $emailEntity, 'lead' => $lead, 'template' => $template)); $content = $response->getContent(); } else { $content = $emailEntity->getCustomHtml(); } $event = new EmailSendEvent(null, array('content' => $content, 'lead' => $lead, 'email' => $emailEntity, 'idHash' => $idHash, 'tokens' => $tokens)); $this->factory->getDispatcher()->dispatch(EmailEvents::EMAIL_ON_DISPLAY, $event); $content = $event->getContent(); } } else { $subject = $copy->getSubject(); $content = $copy->getBody(); } // Convert emoji $content = EmojiHelper::toEmoji($content, 'short'); $subject = EmojiHelper::toEmoji($subject, 'short'); // Replace tokens if (!empty($tokens)) { $content = str_ireplace(array_keys($tokens), $tokens, $content); $subject = str_ireplace(array_keys($tokens), $tokens, $subject); } // Add analytics $analytics = $this->factory->getHelper('template.analytics')->getCode(); // Check for html doc if (strpos($content, '<html>') === false) { $content = "<html>\n<head>{$analytics}</head>\n<body>{$content}</body>\n</html>"; } elseif (strpos($content, '<head>') === false) { $content = str_replace('<html>', "<html>\n<head>\n{$analytics}\n</head>", $content); } elseif (!empty($analytics)) { $content = str_replace('</head>', $analytics . "\n</head>", $content); } // Add subject as title if (!empty($subject)) { if (strpos($content, '<title></title>') !== false) { $content = str_replace('<title></title>', "<title>{$subject}</title>", $content); } elseif (strpos($content, '<title>') === false) { $content = str_replace('<head>', "<head>\n<title>{$subject}</title>", $content); } } return new Response($content); } $this->notFound(); }