<p>You can do this with a simple module. You can set one up at <a href="https://pluginfactory.io" rel="noreferrer">pluginfactory.io</a> with no controllers and a service called Email. If you're unsure about how modules work or how to set one up, I can highly recommend reading Andrew Welch's <a href="https://nystudio107.com/blog/enhancing-a-craft-cms-3-website-with-a-custom-module" rel="noreferrer">guide to creating a module in Craft 3</a>.</p>
<p>In this code, I've called the module 'MyModule' but you can give it any name you like.</p>
<p>Update the main module file's <code>init</code> method to look something like this:</p>
<pre><code>public function init()
{
    parent::init();
    self::$instance = $this;

    // This line calls a private method to register a new email message in Craft
    $this-&gt;_registerEmailMessages();
}
</code></pre>
<p>At the bottom of your main module file, add the <code>_registerEmailMessages()</code> function:</p>
<pre><code>private function _registerEmailMessages()
{
    Event::on(
        SystemMessages::class,
        SystemMessages::EVENT_REGISTER_MESSAGES,
        function(RegisterEmailMessagesEvent $event) {
            $event-&gt;messages = array_merge($event-&gt;messages, [
                [
                    'key' =&gt; 'my-module_publish-notification',
                    'heading' =&gt; Craft::t('my-module', 'my-module_publish-notification_heading'),
                    'subject' =&gt; Craft::t('my-module', 'my-module_publish-notification_subject'),
                    'body' =&gt; Craft::t('my-module', 'my-module_publish-notification_body'),
                ]
            ]);
        }
    );
}
</code></pre>
<p>Note: you'll need to add the correct 'use' statements at the top of your module file, if you're not using an IDE like PhpStorm which adds them automatically:</p>
<pre><code>use craft\events\RegisterEmailMessagesEvent;
use craft\services\SystemMessages;
</code></pre>
<p>What this function does is to add a new system email message with the key 'my-module_publish-notification', with translation strings for the heading, subject and body. This email will be accessible and editable in the CP by going to Utilities &gt; System Messages.</p>
<p>Now you need to add some text to those translation strings. Your Pluginfactory module should come with everything set up for this. Look in the <code>src/translations/en</code> folder and you should find a file named after your module, e.g. 'my-module.php'</p>
<p>In this file, you can add the text that you want to be shown in this email by default:</p>
<pre><code>'my-module_publish-notification_heading' =&gt; 'When an entry is created:',
'my-module_publish-notification_subject' =&gt; 'An entry has been created',
'my-module_publish-notification_body' =&gt; &quot;A new entry has been created by {{ username }}.&quot;,
</code></pre>
<p>The heading is what's shown in the System Messages screen above the email, and the subject and body are exactly what you'd expect: the subject of the email, and the body text of the email.</p>
<p>The next step is to listen to the <code>EVENT_AFTER_SAVE</code> event to trigger the email itself. Add another line to your module's <code>init</code> method:</p>
<pre><code>$this-&gt;installEventListeners();
</code></pre>
<p>Then add the <code>installEventListeners()</code> method at the bottom of the module file:</p>
<pre><code>protected function installEventListeners()
{
    Event::on(
        Entry::class,
        Element::EVENT_AFTER_SAVE,
        function(ModelEvent $event) {
            /** @var Entry $entry */
            $entry = $event-&gt;sender;

            if (ElementHelper::isDraftOrRevision($entry)) {
                return;
            }

            if ($entry-&gt;isNew) {
                $this::$instance-&gt;emailService-&gt;sendEntryNotification($entry);
            }
        }
    );
}
</code></pre>
<p>This method adds a listener which will be called after an entry is saved, and if the entry is a new entry (i.e. it's not an existing entry being edited) then it calls the Email service's <code>sendEntryNotification</code> method.</p>
<p>In your Email service, that method would look something like this:</p>
<pre><code>public function sendEntryNotification(Entry $entry)
{
    $admins = User::find()
        -&gt;admin(true)
        -&gt;all();

    foreach($admins as $admin) {
        $mail = Craft::$app-&gt;getMailer()
            -&gt;composeFromKey('my-module_publish-notification', [
                'username' =&gt; $entry-&gt;author-&gt;username
            ]);

        $mail
            -&gt;setTo($admin)
            -&gt;send();
    }
}
</code></pre>
<p>This method fetches all admins, then loops through each one and sends the notification email as defined by the key that's passed into <code>composeFromKey</code> -  the key should match the string that we set as the key in our <code>_registerEmailMessages</code> function.</p>
<p>You can pass any sort of data through to your email. I've shown how to pass the username of the entry's author, but you can pass any data through in an array as the second argument in <code>composeFromKey</code>. The key of each data can be used in your email's content to show the value. In this example, the translation string for 'my-module_publish-notification_body' shows the username like this:</p>
<pre><code>&quot;A new entry has been created by {{ username }}.&quot;
</code></pre>
<p>You could pass in the name of the user, the creation date and any other data from the entry.</p>
<p>The last step is to register your module with your Craft app. The Pluginfactory download comes with a <code>config</code> directory with an <code>app.php</code> file inside. Copy the code that starts with 'my-module' - it should look something like this:</p>
<pre><code>'my-module' =&gt; [
    'class' =&gt; \modules\mymodule\MyModule::class,
    'components' =&gt; [
        'email' =&gt; [
            'class' =&gt; 'modules\mymodule\services\Email',
        ],
    ],
],
'bootstrap' =&gt; ['my-module'],
</code></pre>
<p>Open up your Craft <code>app.php</code> file, which lives in the root <code>config</code> directory, and add the code from above. This should end up looking something like this:</p>
<pre><code>return [
    '*' =&gt; [
        'modules' =&gt; [
            'my-module' =&gt; [
                'class' =&gt; \modules\mymodule\MyModule::class,
                'components' =&gt; [
                    'email' =&gt; [
                        'class' =&gt; 'modules\mymodule\services\Email',
                    ],
                ],
            ],
        ],
        'bootstrap' =&gt; ['my-module'],
    ],
];
</code></pre>
<p>The final step is to make Composer happy. Add your module to your <code>composer.json</code>'s autoload object:</p>
<pre><code>&quot;autoload&quot;: {
    &quot;psr-4&quot;: {
        &quot;modules\\mymodule\\&quot;: &quot;modules/mymodule/src/&quot;
    }
}
</code></pre>
<p>Then run <code>composer dump-autoload</code> to rebuild the Com­pos­er autoload map.</p>
<p>That should get you almost all of the way there! You may need to update your event listener to make sure it's only calling the email method for the correct section(s) within your site.</p>

CC BY-SA 4.0
2020-11-09T05:30:47.913Z
Great answer, Martin!
Brad Bell
CC BY-SA 4.0
2020-11-06T10:27:42.623Z
2020-11-06T10:40:24.867Z
2020-11-06T10:40:24.867Z
Martin Spain
<p>I was able to get Martin Spain's module working (thank you!) but I did run into a few road blocks due to my version of Craft(3.7.30.1). I've added the updated functions below. You can now select a target entry section i.e. &quot;entrySubmissions&quot; and target email group i.e. &quot;emailNotifications&quot;</p>
<p>Event Listener:</p>
<pre><code>protected function installEventListeners(){
   Event::on(
      Entry::class, 
      Element::EVENT_BEFORE_SAVE, 
      function(ModelEvent $e) {

      /* @var Entry $entry */
      $entry = $e-&gt;sender;

      if (ElementHelper::isDraftOrRevision($entry)) {
        // don’t do anything with drafts or revisions
        return;
      }

      $section = $entry-&gt;section-&gt;handle;

      if ($entry-&gt;firstSave &amp;&amp; $section === 'entrySubmissions') {
         $this::$instance-&gt;sendEntryNotification($entry);
      }
   }
);
}
</code></pre>
<p>Send Entry:</p>
<pre><code>public function sendEntryNotification(Entry $entry){
   $users = \craft\elements\User::find()
   -&gt;group('emailNotifications')
   -&gt;all();


   foreach($users as $user) {
       $mail = Craft::$app-&gt;getMailer()
        -&gt;composeFromKey('email-module_publish-notification', [
            'username' =&gt; $entry-&gt;author-&gt;username
        ]);

    $mail
        -&gt;setTo($user)
        -&gt;send();
 }
}
</code></pre>
<p>And I had to add these to the top of my module file:</p>
<pre><code>use craft\elements\Entry;
use craft\models\Section;
</code></pre>

CC BY-SA 4.0
2022-02-06T02:50:55.933Z
2022-02-06T02:50:55.933Z
Mike Niland
<p>Anyone written a simple plugin that does this out there? When a user submits a form on the frontend, it creates a new entry (with the default status set to disabled). I'd like to set it up so that the admins receive an email notification every time a new disabled entry is created for that section.</p>

CC BY-SA 4.0
2022-02-06T12:02:00.963Z
Check Formie .. have anything you need
user12903
<entry><emails>
Send email notification to admins when a new entry is created
# Send email notification to admins when a new entry is created

(Asked by: username_0 on 2020-11-05)

Anyone written a simple plugin that does this out there? When a user submits a form on the frontend, it creates a new entry (with the default status set to disabled). I'd like to set it up so that the admins receive an email notification every time a new disabled entry is created for that section.

**Tags:** entry, emails
> **Comments:**
> **username_1**: Check Formie .. have anything you need  

---

## 2 answers

### Answer by username_2 on 2020-11-06. Score: 5

You can do this with a simple module. You can set one up at pluginfactory.io with no controllers and a service called Email. If you're unsure about how modules work or how to set one up, I can highly recommend reading Andrew Welch's guide to creating a module in Craft 3.
In this code, I've called the module 'MyModule' but you can give it any name you like.
Update the main module file's init method to look something like this:
public function init()
{
    parent::init();
    self::$instance = $this;

    // This line calls a private method to register a new email message in Craft
    $this->_registerEmailMessages();
}

At the bottom of your main module file, add the _registerEmailMessages() function:
private function _registerEmailMessages()
{
    Event::on(
        SystemMessages::class,
        SystemMessages::EVENT_REGISTER_MESSAGES,
        function(RegisterEmailMessagesEvent $event) {
            $event->messages = array_merge($event->messages, [
                [
                    'key' => 'my-module_publish-notification',
                    'heading' => Craft::t('my-module', 'my-module_publish-notification_heading'),
                    'subject' => Craft::t('my-module', 'my-module_publish-notification_subject'),
                    'body' => Craft::t('my-module', 'my-module_publish-notification_body'),
                ]
            ]);
        }
    );
}

Note: you'll need to add the correct 'use' statements at the top of your module file, if you're not using an IDE like PhpStorm which adds them automatically:
use craft\events\RegisterEmailMessagesEvent;
use craft\services\SystemMessages;

What this function does is to add a new system email message with the key 'my-module_publish-notification', with translation strings for the heading, subject and body. This email will be accessible and editable in the CP by going to Utilities > System Messages.
Now you need to add some text to those translation strings. Your Pluginfactory module should come with everything set up for this. Look in the src/translations/en folder and you should find a file named after your module, e.g. 'my-module.php'
In this file, you can add the text that you want to be shown in this email by default:
'my-module_publish-notification_heading' => 'When an entry is created:',
'my-module_publish-notification_subject' => 'An entry has been created',
'my-module_publish-notification_body' => "A new entry has been created by {{ username }}.",

The heading is what's shown in the System Messages screen above the email, and the subject and body are exactly what you'd expect: the subject of the email, and the body text of the email.
The next step is to listen to the EVENT_AFTER_SAVE event to trigger the email itself. Add another line to your module's init method:
$this->installEventListeners();

Then add the installEventListeners() method at the bottom of the module file:
protected function installEventListeners()
{
    Event::on(
        Entry::class,
        Element::EVENT_AFTER_SAVE,
        function(ModelEvent $event) {
            /** @var Entry $entry */
            $entry = $event->sender;

            if (ElementHelper::isDraftOrRevision($entry)) {
                return;
            }

            if ($entry->isNew) {
                $this::$instance->emailService->sendEntryNotification($entry);
            }
        }
    );
}

This method adds a listener which will be called after an entry is saved, and if the entry is a new entry (i.e. it's not an existing entry being edited) then it calls the Email service's sendEntryNotification method.
In your Email service, that method would look something like this:
public function sendEntryNotification(Entry $entry)
{
    $admins = User::find()
        ->admin(true)
        ->all();

    foreach($admins as $admin) {
        $mail = Craft::$app->getMailer()
            ->composeFromKey('my-module_publish-notification', [
                'username' => $entry->author->username
            ]);

        $mail
            ->setTo($admin)
            ->send();
    }
}

This method fetches all admins, then loops through each one and sends the notification email as defined by the key that's passed into composeFromKey -  the key should match the string that we set as the key in our _registerEmailMessages function.
You can pass any sort of data through to your email. I've shown how to pass the username of the entry's author, but you can pass any data through in an array as the second argument in composeFromKey. The key of each data can be used in your email's content to show the value. In this example, the translation string for 'my-module_publish-notification_body' shows the username like this:
"A new entry has been created by {{ username }}."

You could pass in the name of the user, the creation date and any other data from the entry.
The last step is to register your module with your Craft app. The Pluginfactory download comes with a config directory with an app.php file inside. Copy the code that starts with 'my-module' - it should look something like this:
'my-module' => [
    'class' => \modules\mymodule\MyModule::class,
    'components' => [
        'email' => [
            'class' => 'modules\mymodule\services\Email',
        ],
    ],
],
'bootstrap' => ['my-module'],

Open up your Craft app.php file, which lives in the root config directory, and add the code from above. This should end up looking something like this:
return [
    '*' => [
        'modules' => [
            'my-module' => [
                'class' => \modules\mymodule\MyModule::class,
                'components' => [
                    'email' => [
                        'class' => 'modules\mymodule\services\Email',
                    ],
                ],
            ],
        ],
        'bootstrap' => ['my-module'],
    ],
];

The final step is to make Composer happy. Add your module to your composer.json's autoload object:
"autoload": {
    "psr-4": {
        "modules\\mymodule\\": "modules/mymodule/src/"
    }
}

Then run composer dump-autoload to rebuild the Com­pos­er autoload map.
That should get you almost all of the way there! You may need to update your event listener to make sure it's only calling the email method for the correct section(s) within your site.

> **Comments:**
> **username_3**: Great answer, Martin!  

---

### Answer by username_4 on 2022-02-06. Score: 1

I was able to get Martin Spain's module working (thank you!) but I did run into a few road blocks due to my version of Craft(3.7.30.1). I've added the updated functions below. You can now select a target entry section i.e. "entrySubmissions" and target email group i.e. "emailNotifications"
Event Listener:
protected function installEventListeners(){
   Event::on(
      Entry::class, 
      Element::EVENT_BEFORE_SAVE, 
      function(ModelEvent $e) {

      /* @var Entry $entry */
      $entry = $e->sender;

      if (ElementHelper::isDraftOrRevision($entry)) {
        // don’t do anything with drafts or revisions
        return;
      }

      $section = $entry->section->handle;

      if ($entry->firstSave && $section === 'entrySubmissions') {
         $this::$instance->sendEntryNotification($entry);
      }
   }
);
}

Send Entry:
public function sendEntryNotification(Entry $entry){
   $users = \craft\elements\User::find()
   ->group('emailNotifications')
   ->all();


   foreach($users as $user) {
       $mail = Craft::$app->getMailer()
        ->composeFromKey('email-module_publish-notification', [
            'username' => $entry->author->username
        ]);

    $mail
        ->setTo($user)
        ->send();
 }
}

And I had to add these to the top of my module file:
use craft\elements\Entry;
use craft\models\Section;


---

