Answers.Body: <p>If you have questions or other issues feel free to ask.<br>
  Please don't be confused, my Plugins handle/name is "Test" because I only use it for these purposes.. So whenever you see the name "Test" you know you have to rename it</p>
  
  <p>This is your plugins init function</p>
  
  <pre><code>/**
   * Called after the plugin class is instantiated; do any one-time initialization here such as hooks and events:
   * @return mixed
   */
  public function init()
  {
      parent::init();
      craft()-&gt;on('entries.onBeforeSaveEntry', function(Event $event)
      {
          // trigger only when entries are changed not when created
          if(!$event-&gt;params['isNewEntry']){
              /** @var EntryModel $entry */
              $entry = $event-&gt;params['entry'];
              // create your logic to check if it is the correct entry...
              // you should check for your section here otherwise you'll send a mail for all updates^^
              // I just used the handle pages in my test system
              if($entry-&gt;getSection()-&gt;handle === "pages"){
                  // next: fetch all user related to the entry...
                  // since I don't know your entire fields, you have to implement the logic
                  // to fetch users from entries that are related to the entry yourself
                  // if you need help just ask
                  $criteria = craft()-&gt;elements-&gt;getCriteria(ElementType::User);
                  $criteria-&gt;relatedTo($entry);
  
                  /** @var UserModel $user */
                  foreach( $criteria as $user){
                      // create a new entry in the database
                      $email = new Test_EmailRecord();
                      $email-&gt;entryId = $entry-&gt;id;
                      $email-&gt;email = $user-&gt;email;
                      $email-&gt;save();
                  }
              }
          }
  
      });
  }
  </code></pre>
  
  <p>And you have to create the following record</p>
  
  <pre><code>namespace Craft;
  
  
  class Test_EmailRecord extends BaseRecord
  {
      public function getTableName()
      {
          return 'cron_mails';
      }
  
      protected function defineAttributes()
      {
          return array(
              // you could store the user Id here too, but this way
              // you can send the mail to non users too
              'email' =&gt; AttributeType::String,
              'entryId' =&gt; array(AttributeType::Number),
          );
      }
  
      // you could - if you want - create relations here..
      // https://craftcms.com/docs/plugins/records#defining-relations
      // but since it's only an example and not needed I skipped that part
  }
  </code></pre>
  
  <p>And you need this in your controller</p>
  
  <pre><code> /**
   * Cronjob to send emails... you can activate it every X hours
   * or once per day or whatever you want
   * when this function is trigger a specific number of mails will be send
   * their entries in the database will be deleted until there are no rows in the
   * table
   */
  public function actionSendMails()
  {
      // fetch mails with limit.. insert your limit here.. I would suggest to fetch 20-50
      // entries per trigger depending on how often it should run
      $emails = Test_EmailRecord::model()-&gt;findAllBySql('select * from craft_cron_mails LIMIT 1');
  
      if (is_array($emails) &amp;&amp; count($emails)) {
          foreach ($emails as $email) {
              /** @var UserModel $user */
              $user = craft()-&gt;users-&gt;getUserByEmail($email-&gt;email);
  
              // do your logic if no user is found..
              // of course you could store the user Id rather than the email in the database table
              // but this way you can send the mail to non users too if you like
              if (!$user) {
                  // you can just remove that part
                  // I just wanted to show you could create an array with defaults here
                  // if the user is not registered
                  $user = array(/* fill some placeholders for your twig template */);
              }
  
              // prepare templates, you can address each user personally with a hello Mr {{ user.name }}
              // the entry {{ entry.title }} was edited and such... 
              $message = craft()-&gt;templates-&gt;render('path/to/template.twig', array(
                  'user' =&gt; $user,
                  'entry' =&gt; craft()-&gt;elements-&gt;getElementById($email-&gt;entryId)
              ));
              if ($this-&gt;sendMail($message, "The post was edited", $user-&gt;email)) {
                  //remove the column if the mail was send
                  $email-&gt;delete();
              }
  
          }
      }
  }
  
  /**
   * This function sends the mail, it usually belongs to a service
   * but to make it easier I'll just leave it here
   *
   * @param $message
   * @param $subject
   * @param null $mail
   * @return bool
   */
  public function sendMail($message, $subject, $mail = null)
  {
      $errors = false;
      $adminEmail = craft()-&gt;systemSettings-&gt;getSetting('email', 'emailAddress');
  
      $email = new EmailModel();
  
      $email-&gt;fromEmail = $adminEmail;
      $email-&gt;replyTo = $adminEmail;
      $email-&gt;sender = $adminEmail;
      $email-&gt;fromName = craft()-&gt;getSiteName();
      $email-&gt;toEmail = $mail;
      $email-&gt;subject = $subject;
      $email-&gt;body = $message;
  
      if (!craft()-&gt;email-&gt;sendEmail($email)) {
          $errors = true;
      }
  
      return $errors;
  }
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-10-22T15:16:28.293Z
Answers.Text: Wow, this looks super! Going to take me a short while to digest this and test it. Your help is very much appreciated! I’ll respond once I’ve had a play! Thanks
Answers.UserDisplayName: shorn
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-10-26T19:18:46.997Z
Answers.Text: Just looking at tackling this now and I think there might be a better way to do this. As I mentioned, this is for a basic commenting system. One way I was thinking of doing it would be to get get a notification only if someone replies directly to you, rather than setting up a users field. So, the user woudl hit reply under another comment and I can pass that users id to the new comment that gets posted and send an email to that user. That way, only 1 additional email is getting generated. Would save setting up and record and cron job. Make sense?
Answers.UserDisplayName: shorn
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-10-26T19:25:59.780Z
Answers.Text: It's totally up to you. If you think it might be enough to only notify one user you can do that as well. Some systems do it this way, some system inform everyone. If you only want to inform one user you can just render the email message and send it after your `saveEntry` from before is successfull
Answers.UserDisplayName: Robin Schambach
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-10-26T19:29:51.633Z
Answers.Text: Yea, I think this might be best. I've been in some threads where I get notified of every message and soon wish I hadn't :)
Answers.UserDisplayName: shorn
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-10-26T19:32:25.710Z
Answers.Text: Okay, then you can at least use the Sendmail function. Glad I could help you anyway.
Answers.UserDisplayName: Robin Schambach
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-10-26T19:37:48.453Z
Answers.Text: Will do, I already have some of the email stuff setup and working so it will be a case of extending that. Going to mark the answer as solved anyway as it was a reasonable solution. You help has been much appreciated! Many thanks,
Answers.UserDisplayName: shorn
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-10-22T15:10:57.100Z
Answers.LastActivityDate: 2017-10-22T16:13:30.747Z
Answers.LastEditDate: 2017-10-22T16:13:30.747Z
Answers.UserDisplayName: Robin Schambach
Body: <p>I have a channel set up with front end submitted entries. I want a way for users to be able to subscribe themselves to receive an update whenever the entry (or it's related entries) are updated. I was thinking one way to so this so that it can be managed on the front end would be to add a Users field to the entry and let logged in users add themselves to it.</p>
  
  <p>I have a simple notification service that I am using in a custom plugin that is sending emails to entry authors, but I'm not sure how, or what would be the best way to send emails to multiple users as per the above requirement.</p>
  
  <p>(p.s I'm new and limited in my plugin knowledge!)</p>
  
  <p>Any thoughts or suggestions. </p>
  
  <p>Thanks!</p>
  
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2017-10-22T13:40:45.760Z
Comments.Text: There is an easy and a "more complex" way to achieve this, it depends on how many people will subscribe in one entry. You could just hook yourself on the `entry.onUpdate` method and send a mail to all users. That would be only a few lines (I'll write them) but if you think there could be 20+ people in one entry with frequent updates you have to collect all mails in a table and create a cron job to send them. It's easy but requires much more code (when you use craft 2,with craft 3 it's less).
Comments.UserDisplayName: Robin Schambach
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2017-10-22T13:56:07.493Z
Comments.Text: Ah ok. That makes sense. I think the entries are quite likely to have 20+ users. That was my concern in whether that field starts getting large. It’s essentially a comments section that’s set up, so the notifications would be for when people have commented.
Comments.UserDisplayName: shorn
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2017-10-22T14:06:18.340Z
Comments.Text: It's not about a field getting large, you can relate as many people as you want with an entry. There is no restriction in the database since every user has its own row in the relations table. It's more about the performance. You can't send all mails when one user submits something because this one user has to wait for all mails to be send until he gets a response. So if there are 100+ people the request could be rejected due to server time restrictions. Do you use a custom controller/service to save entries? I'll provide a solution after your answer
Comments.UserDisplayName: Robin Schambach
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2017-10-22T14:52:44.920Z
Comments.Text: Indeed, that’s what I meant, not so much the amount of users, but the effect that has on running something like notification mails. No custom controller/service. Just standard entries.
Comments.UserDisplayName: shorn
Tags: <plugin-development><emails>
Title: Plugin sending emails to all users in an entries Users field
ThreadText: # Plugin sending emails to all users in an entries Users field
  
  (Asked by: username_0 on 2017-10-22)
  
  I have a channel set up with front end submitted entries. I want a way for users to be able to subscribe themselves to receive an update whenever the entry (or it's related entries) are updated. I was thinking one way to so this so that it can be managed on the front end would be to add a Users field to the entry and let logged in users add themselves to it.
  
  I have a simple notification service that I am using in a custom plugin that is sending emails to entry authors, but I'm not sure how, or what would be the best way to send emails to multiple users as per the above requirement.
  
  (p.s I'm new and limited in my plugin knowledge!)
  
  Any thoughts or suggestions.
  
  Thanks!
  
  **Tags:** plugin-development, emails
  
  > **Comments:**
  > **username_1**: There is an easy and a "more complex" way to achieve this, it depends on how many people will subscribe in one entry. You could just hook yourself on the `entry.onUpdate` method and send a mail to all users. That would be only a few lines (I'll write them) but if you think there could be 20+ people in one entry with frequent updates you have to collect all mails in a table and create a cron job to send them. It's easy but requires much more code (when you use craft 2,with craft 3 it's less).  
  > **username_0**: Ah ok. That makes sense. I think the entries are quite likely to have 20+ users. That was my concern in whether that field starts getting large. It’s essentially a comments section that’s set up, so the notifications would be for when people have commented.  
  > **username_1**: It's not about a field getting large, you can relate as many people as you want with an entry. There is no restriction in the database since every user has its own row in the relations table. It's more about the performance. You can't send all mails when one user submits something because this one user has to wait for all mails to be send until he gets a response. So if there are 100+ people the request could be rejected due to server time restrictions. Do you use a custom controller/service to save entries? I'll provide a solution after your answer  
  > **username_0**: Indeed, that’s what I meant, not so much the amount of users, but the effect that has on running something like notification mails. No custom controller/service. Just standard entries.  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_1 on 2017-10-22. Score: 3 | Accepted answer
  
  If you have questions or other issues feel free to ask.  
  Please don't be confused, my Plugins handle/name is "Test" because I only use it for these purposes.. So whenever you see the name "Test" you know you have to rename it
  
  This is your plugins init function
  
  ```
  /**
   * Called after the plugin class is instantiated; do any one-time initialization here such as hooks and events:
   * @return mixed
   */
  public function init()
  {
      parent::init();
      craft()->on('entries.onBeforeSaveEntry', function(Event $event)
      {
          // trigger only when entries are changed not when created
          if(!$event->params['isNewEntry']){
              /** @var EntryModel $entry */
              $entry = $event->params['entry'];
              // create your logic to check if it is the correct entry...
              // you should check for your section here otherwise you'll send a mail for all updates^^
              // I just used the handle pages in my test system
              if($entry->getSection()->handle === "pages"){
                  // next: fetch all user related to the entry...
                  // since I don't know your entire fields, you have to implement the logic
                  // to fetch users from entries that are related to the entry yourself
                  // if you need help just ask
                  $criteria = craft()->elements->getCriteria(ElementType::User);
                  $criteria->relatedTo($entry);
  
                  /** @var UserModel $user */
                  foreach( $criteria as $user){
                      // create a new entry in the database
                      $email = new Test_EmailRecord();
                      $email->entryId = $entry->id;
                      $email->email = $user->email;
                      $email->save();
                  }
              }
          }
  
      });
  }
  
  ```
  
  And you have to create the following record
  
  ```
  namespace Craft;
  
  class Test_EmailRecord extends BaseRecord
  {
      public function getTableName()
      {
          return 'cron_mails';
      }
  
      protected function defineAttributes()
      {
          return array(
              // you could store the user Id here too, but this way
              // you can send the mail to non users too
              'email' => AttributeType::String,
              'entryId' => array(AttributeType::Number),
          );
      }
  
      // you could - if you want - create relations here..
      // https://craftcms.com/docs/plugins/records#defining-relations
      // but since it's only an example and not needed I skipped that part
  }
  
  ```
  
  And you need this in your controller
  
  ```
   /**
   * Cronjob to send emails... you can activate it every X hours
   * or once per day or whatever you want
   * when this function is trigger a specific number of mails will be send
   * their entries in the database will be deleted until there are no rows in the
   * table
   */
  public function actionSendMails()
  {
      // fetch mails with limit.. insert your limit here.. I would suggest to fetch 20-50
      // entries per trigger depending on how often it should run
      $emails = Test_EmailRecord::model()->findAllBySql('select * from craft_cron_mails LIMIT 1');
  
      if (is_array($emails) && count($emails)) {
          foreach ($emails as $email) {
              /** @var UserModel $user */
              $user = craft()->users->getUserByEmail($email->email);
  
              // do your logic if no user is found..
              // of course you could store the user Id rather than the email in the database table
              // but this way you can send the mail to non users too if you like
              if (!$user) {
                  // you can just remove that part
                  // I just wanted to show you could create an array with defaults here
                  // if the user is not registered
                  $user = array(/* fill some placeholders for your twig template */);
              }
  
              // prepare templates, you can address each user personally with a hello Mr {{ user.name }}
              // the entry {{ entry.title }} was edited and such... 
              $message = craft()->templates->render('path/to/template.twig', array(
                  'user' => $user,
                  'entry' => craft()->elements->getElementById($email->entryId)
              ));
              if ($this->sendMail($message, "The post was edited", $user->email)) {
                  //remove the column if the mail was send
                  $email->delete();
              }
  
          }
      }
  }
  
  /**
   * This function sends the mail, it usually belongs to a service
   * but to make it easier I'll just leave it here
   *
   * @param $message
   * @param $subject
   * @param null $mail
   * @return bool
   */
  public function sendMail($message, $subject, $mail = null)
  {
      $errors = false;
      $adminEmail = craft()->systemSettings->getSetting('email', 'emailAddress');
  
      $email = new EmailModel();
  
      $email->fromEmail = $adminEmail;
      $email->replyTo = $adminEmail;
      $email->sender = $adminEmail;
      $email->fromName = craft()->getSiteName();
      $email->toEmail = $mail;
      $email->subject = $subject;
      $email->body = $message;
  
      if (!craft()->email->sendEmail($email)) {
          $errors = true;
      }
  
      return $errors;
  }
  
  ```
  
  > **Comments:**
  > **username_0**: Wow, this looks super! Going to take me a short while to digest this and test it. Your help is very much appreciated! I’ll respond once I’ve had a play! Thanks  
  > **username_0**: Just looking at tackling this now and I think there might be a better way to do this. As I mentioned, this is for a basic commenting system. One way I was thinking of doing it would be to get get a notification only if someone replies directly to you, rather than setting up a users field. So, the user woudl hit reply under another comment and I can pass that users id to the new comment that gets posted and send an email to that user. That way, only 1 additional email is getting generated. Would save setting up and record and cron job. Make sense?  
  > **username_1**: It's totally up to you. If you think it might be enough to only notify one user you can do that as well. Some systems do it this way, some system inform everyone. If you only want to inform one user you can just render the email message and send it after your `saveEntry` from before is successfull  
  > **username_0**: Yea, I think this might be best. I've been in some threads where I get notified of every message and soon wish I hadn't :)  
  > **username_1**: Okay, then you can at least use the Sendmail function. Glad I could help you anyway.  
  > **username_0**: Will do, I already have some of the email stuff setup and working so it will be a case of extending that. Going to mark the answer as solved anyway as it was a reasonable solution. You help has been much appreciated! Many thanks,  
  
  ---
  
  