I'm developing a Joomla plugin with onContentAfterSave event to send an email after saving a new articles.
the event are triggered when i save a new menu item or a new category.
but not for new article.
Joomla! 3.7.5
public function onContentAfterSave($context, $article, $isNew){
$link = JRoute::_(ContentHelperRoute::getArticleRoute( $article->id, $article->catid ));
$mailer = JFactory::getMailer();
$config = JFactory::getConfig();
$sender = array(
$config->get( 'mailfrom' ),
$config->get( 'fromname' )
);
$mailer->setSender($sender);
$user = JFactory::getUser();
$recipient = $user->email;
$recipient = array($recipient);
$mailer->addRecipient($recipient);
$body = '<p>Bonjour</p>'
.'Un nouveau article a été ajouté.';
$mailer->isHtml(true);
$mailer->Encoding = 'base64';
$mailer->setSubject('Nouveau article - BBN Times');
$mailer->setBody($body);
$send = $mailer->Send();
if ( $send !== true ) {
echo 'Error sending email: ';
} else {
echo 'Mail sent';
}
return true;
}
The onContentAfterSave is triggered by the Joomla core, and not by the extension's model, which means it should be triggered by any content saving.
I can think of 2 reasons why it is not triggered in your case:
You have a condition in your constructor checking for the extension type and only allowing certain extensions to use that event (or somewhere else in your plugin).
You have an error in the code above.
Related
Using Contact Form 7, I need to add additional content to the 'body' of the message. Based on the googles and many searches here, I came up with this:
add_action ('wpcf7_before_send_mail', 'cellarweb_add_to_message', 10, 2);
function cellarweb_add_to_message($additional_mail, $contact_form) {
$submission = WPCF7_Submission::get_instance();
$wpcf7 = WPCF7_ContactForm::get_current();
$extracontent = "<p>This is more text for the message body.</p>";
$mail = $wpcf7->prop('mail');
$mail['mail']['body'].= $extracontent ;
// Save the email body
$wpcf7->set_properties(array(
"mail" => $mail
));
return $wpcf7;
}
I suspect I am not using the right object, or not modifying the right object.
What is the proper way to add text to the CF7 message body?
I think you are missing space while appending the content. Please check the below code.
add_action( 'wpcf7_before_send_mail', 'wpcf7_add_text_to_mail_body' );
function wpcf7_add_text_to_mail_body($contact_form){
$mail = $contact_form->prop( 'mail' );
$wpcf7 = WPCF7_ContactForm::get_current();
$submission = WPCF7_Submission::get_instance();
if ($submission) {
$posted_data = $submission->get_posted_data();
}
$extracontent = "<p>This is more text for the message body.</p>";
$mail['body'] .= '<br>';
$mail['body'] .= $extracontent
$contact_form->set_properties( array( 'mail' => $mail ) );
}
I'm writing a hook using the ProcessWire API... pretty common practice with it's powerful API.
The below works completely fine...
$this->addHookAfter('Pages::saved', function(HookEvent $event) {
$arguments = $event->arguments();
$page = $event->arguments(0);
if ($page->template == 'user') {
// Require relevent libraries
require_once($this->config->paths->root . 'api/sendgrid/sendgrid-php.php');
// SendGrid API init
$sgAPIKey = "XXXX";
// Set email confirmation settings
$email_admin = 'test#example.com';
$email_customer = $page->email;
$email_admin_subject = "You added a new user $page->name";
$email_customer_subject = 'Your login details';
$from = new \SendGrid\Email("Example User", $email_admin);
$subject = "Sending with SendGrid is Fun";
$to = new \SendGrid\Email("Example User", $email_customer);
$content = new \SendGrid\Content("text/plain", "and easy to do anywhere, even with PHP");
$mail = new \SendGrid\Mail($from, $subject, $to, $content);
$sg = new \SendGrid($sgAPIKey);
$response = $sg->client->mail()->send()->post($mail);
// Dump SendGrid object with TracyDebugger
bd($mail);
}
});
However, as soon as I add a function to send the email (in order to set up two separate send mail functions (one to admin, one to customer) it doesn't work at all. No errors... just $mail returns NULL.
$this->addHookAfter('Pages::saved', function(HookEvent $event) {
$arguments = $event->arguments();
$page = $event->arguments(0);
if ($page->template == 'user') {
// Require relevent libraries
require_once($this->config->paths->root . 'api/sendgrid/sendgrid-php.php');
// SendGrid API init
$sgAPIKey = "XXXX";
// Set email confirmation settings
$email_admin = 'test#example.com';
$email_customer = $page->email;
$email_admin_subject = "You added a new user $page->name";
$email_customer_subject = 'Your login details';
$email_customer_body = 'This is a test';
function send_email($from_email, $to_email, $subject, $body) {
global $sgAPIKey;
$from = new \SendGrid\Email(null, $from_email);
$to = new \SendGrid\Email(null, $to_email);
$content = new \SendGrid\Content("text/html", $body);
$mail = new \SendGrid\Mail($from, $subject, $to, $content);
$sg = new \SendGrid($sgAPIKey);
$response = $sg->client->mail()->send()->post($mail);
}
send_email($email_admin, $email_customer, $email_customer_subject, $email_customer_body);
// Dump SendGrid object with TracyDebugger
global $mail;
bd($mail);
}
});
Is there any reason why a function like this wouldn't work? Is it because technically there's a function inside a function? I would've at least have thought it would've returned an error.
Functions inside of functions are allowed in PHP, however the issue that you are experiencing is more of an issue with scoping. $mail is no longer in scope after that function is completed, meaning, among other things, that you can no longer access that variable.
One possible solution is to return that variable when the function completes, like so:
function send_email($from_email, $to_email, $subject, $body) {
global $sgAPIKey;
$from = new \SendGrid\Email(null, $from_email);
$to = new \SendGrid\Email(null, $to_email);
$content = new \SendGrid\Content("text/html", $body);
$mail = new \SendGrid\Mail($from, $subject, $to, $content);
$sg = new \SendGrid($sgAPIKey);
$response = $sg->client->mail()->send()->post($mail);
return $mail;
}
That way, when you execute the function, you can set it to a variable.
As an aside, I noticed you attempted to use the global keyword to access that $mail variable. Not only is that typically frowned upon as bad practice, it would never work in this context. The global keyword is used to make variables that are in the global namespace accessable. The typical use is as follows:
$global_variable = "foobar";
class Foo {
public static function test() {
return $global_variable;
}
public static function test_two() {
global $global_variable;
return $global_variable;
}
}
echo(Foo::test()); //echoes nothing, since in scope, the variable is not set
echo(Foo::test_two()); //echoes 'foobar', since we told PHP to put it in scope
TLDR: The global keyword makes variables that are in the global scope, be visible in the local scope.
I would like to send emails only to users that have completed a specific course and add a pdf file (a certificate for completing the course) as attachment to the email, and do so at a specific time using moodle cron.
I have looked at some plugins to find out how it's done, but I'm still not sure how exactly I should do this.
I need:
1. to know how I would add an attachment to an email (and which API to use),
2. how I would use cron to send the emails to the desired group at a certain time,
3. how to retrieve users that have completed the course so that I could send emails (with attachment) to them.
Thanks in advance.
(I'm using moodle version 3.0)
This is an overview.
First create a local plugin. For example /local/yourplugin
https://docs.moodle.org/dev/Local_plugins
Then set up a message provider
https://docs.moodle.org/dev/Message_API
defined('MOODLE_INTERNAL') || die();
in local/yourplugin/db/messages.php
$messageproviders = array (
'coursecompleted' => array (
),
Then add an event observer - you will want to respond to the course_completed event
https://docs.moodle.org/dev/Event_2
in /local/yourpluginname/db/events.php
have something like
$observers = array(
array(
'eventname' => '\core\event\course_completed',
'callback' => 'local_yourplugin_observer::course_completed',
),
);
Now add the message code
Add something like this to '/local/message/classes/observer.php'
defined('MOODLE_INTERNAL') || die();
class local_yourplugin_observer {
/**
* Triggered when 'course_completed' event is triggered.
*
* #param \core\event\course_completed $event
* #return bool
*/
public static function course_completed(\core\event\course_completed $event) {
// Your code here.
$message = new \core\message\message();
$message->component = 'local_yourplugin'; // Name of your local plugin.
$message->name = 'coursecompleted'; // Name of message provider.
$message->userfrom = $USER;
$message->userto = $user;
$message->subject = 'message subject 1';
$message->fullmessage = 'message body';
$message->fullmessageformat = FORMAT_MARKDOWN;
$message->fullmessagehtml = '<p>message body</p>';
$message->smallmessage = 'small message';
$message->notification = '0';
$message->contexturl = 'http://GalaxyFarFarAway.com';
$message->contexturlname = 'Context name';
$message->replyto = "random#example.com";
$content = array('*' => array('header' => ' test ', 'footer' => ' test ')); // Extra content for specific processor
$message->set_additional_content('email', $content);
// Create a file instance.
$usercontext = context_user::instance($user->id);
$file = new stdClass;
$file->contextid = $usercontext->id;
$file->component = 'user';
$file->filearea = 'private';
$file->itemid = 0;
$file->filepath = '/';
$file->filename = '1.txt';
$file->source = 'test';
$fs = get_file_storage();
$file = $fs->create_file_from_string($file, 'file1 content');
$message->attachment = $file;
$messageid = message_send($message);
}
}
i am trying to set html on the output of the email send by joomla. my file is located in the joomla core.
i know i have to add something like ->isHTML(true); but i do not know where and how.
here is the code:
class MailtoController extends JControllerLegacy
{
/**
* Show the form so that the user can send the link to someone.
*
* #return void
*
* #since 1.5
*/
public function mailto()
{
$session = JFactory::getSession();
$session->set('com_mailto.formtime', time());
$this->input->set('view', 'mailto');
$this->display();
}
public function send()
{
// Check for request forgeries
JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN'));
$app = JFactory::getApplication();
$session = JFactory::getSession();
$timeout = $session->get('com_mailto.formtime', 0);
if ($timeout == 0 || time() - $timeout < 1)
{
JError::raiseNotice(500, JText::_('COM_MAILTO_EMAIL_NOT_SENT'));
return $this->mailto();
}
$SiteName = $app->get('sitename');
$link = MailtoHelper::validateHash($this->input->get('link', '', 'post'));
// Verify that this is a local link
if (!$link || !JUri::isInternal($link))
{
// Non-local url...
JError::raiseNotice(500, JText::_('COM_MAILTO_EMAIL_NOT_SENT'));
return $this->mailto();
}
// An array of email headers we do not want to allow as input
$headers = array (
'Content-Type:',
'MIME-Version:',
'Content-Transfer-Encoding:',
'bcc:',
'cc:'
);
// An array of the input fields to scan for injected headers
$fields = array(
'mailto',
'sender',
'from',
'subject',
);
/*
* Here is the meat and potatoes of the header injection test. We
* iterate over the array of form input and check for header strings.
* If we find one, send an unauthorized header and die.
*/
foreach ($fields as $field)
{
foreach ($headers as $header)
{
if (strpos($_POST[$field], $header) !== false)
{
JError::raiseError(403, '');
}
}
}
/*
* Free up memory
*/
unset ($headers, $fields);
$email = $this->input->post->getString('mailto', '');
$sender = $this->input->post->getString('sender', '');
$from = $this->input->post->getString('from', '');
$subject_default = JText::sprintf('COM_MAILTO_SENT_BY', $sender);
$subject = $this->input->post->getString('subject', $subject_default);
// Check for a valid to address
$error = false;
if (!$email || !JMailHelper::isEmailAddress($email))
{
$error = JText::sprintf('COM_MAILTO_EMAIL_INVALID', $email);
JError::raiseWarning(0, $error);
}
// Check for a valid from address
if (!$from || !JMailHelper::isEmailAddress($from))
{
$error = JText::sprintf('COM_MAILTO_EMAIL_INVALID', $from);
JError::raiseWarning(0, $error);
}
if ($error)
{
return $this->mailto();
}
// Build the message to send
$msg = JText::_('COM_MAILTO_EMAIL_MSG');
$link = $link;
//$body = sprintf($msg, $SiteName, $sender, $from, $link);
$body = "<p>Hello Test F,</p><br/><p>Thank you for registering at Deals&offers. Your account is created and activated.</p><br/>You may login to ".$SiteName." using the following username and password:</br><p>Username: ".$sender."</p><p>Password: ".$from."/p><br/><p><b>Note:</b> It is recomended to change your password after first login. ".$link."</p>";
// Clean the email data
$subject = JMailHelper::cleanSubject($subject);
$body = JMailHelper::cleanBody($body);
// To send we need to use punycode.
$from = JStringPunycode::emailToPunycode($from);
$from = JMailHelper::cleanAddress($from);
$email = JStringPunycode::emailToPunycode($email);
// Send the email
if (JFactory::getMailer()->sendMail($from, $sender, $email, $subject, $body) !== true)
{
JError::raiseNotice(500, JText::_('COM_MAILTO_EMAIL_NOT_SENT'));
return $this->mailto();
}
JFactory::getApplication()->enqueueMessage('ok!', '');
$this->input->set('view', 'sent');
$this->display();
}
}
thank you very much
you can add before body or between subject and body . however, it must be before the submit command !!
here is an example of PhpMailler firstly, you need to call the class like this and you can use it
$this->mail= new PHPMailer();
$this->mail->IsSMTP();
$this->mailIsHTML(true);
$subject = JMailHelper::cleanSubject($subject);
$body = JMailHelper::cleanBody($body);
however if the function is static also you call the function in same class
you can call the function by sef command
self::mailIsHTML(true)
I'm new to using EWS from Exchangeclient classes.
I'm looking for a simple example how to send an email with an attachment. I've found examples about how to send an email but not sending an email with an attachment.
This is my script:
$exchangeclient = new Exchangeclient();
$exchangeclient->init($username, $password, NULL, 'ews/Services.wsdl');
$exchangeclient->send_message($mail_from, $subject, $body, 'HTML', true, true);
function - PHP Classes:
function send_message($to, $subject, $content, $bodytype="Text", $saveinsent=true, $markasread=true) {
$this->setup();
if($saveinsent) {
$CreateItem->MessageDisposition = "SendOnly";
$CreateItem->SavedItemFolderId->DistinguishedFolderId->Id = "sentitems";
}
else
$CreateItem->MessageDisposition = "SendOnly";
$CreateItem->Items->Message->ItemClass = "IPM.Note";
$CreateItem->Items->Message->Subject = $subject;
$CreateItem->Items->Message->Body->BodyType = $bodytype;
$CreateItem->Items->Message->Body->_ = $content;
$CreateItem->Items->Message->ToRecipients->Mailbox->EmailAddress = $to;
if($markasread)
$CreateItem->Items->Message->IsRead = "true";
$response = $this->client->CreateItem($CreateItem);
$this->teardown();
if($response->ResponseMessages->CreateItemResponseMessage->ResponseCode == "NoError")
return true;
else {
$this->lastError = $response->ResponseMessages->CreateItemResponseMessage->ResponseCode;
return false;
}
}
You have to first save the email as a draft (with the appropriate message disposition), then CreateAttachment() so it has an attachment, then edit it with UpdateItem() so the message disposition is SendOnly. Then it will be sent.
See David Sterling's reply on this thread: http://social.technet.microsoft.com/Forums/en-US/exchangesvrdevelopment/thread/f7d5257e-ec98-40fd-b301-f378ba3080fd/ (It's about Meeting Requests but they work the same way.)