People ask this every week: “My client gets a daily email (a newsletter, an AI news summary, a report). Can it go on the blog automatically?” The answers are usually “use Jetpack” or “use Zapier”. WordPress has had this built in since its early days. It’s just poorly explained.
Where it is
Settings → Writing → Post via email. You enter a mailbox’s POP3 server, port, login and password, and choose a category for emailed posts.
What it does, step by step
These come from reading core’s wp-mail.php and testing it against a real mailbox:
- It needs a secret mailbox. Every email that arrives there becomes a post. Use an address nobody can guess, and nothing else should be delivered to it.
- Nothing checks the mailbox by itself. WordPress only reads it when someone opens
yoursite.com/wp-mail.php. Many people set it up, see nothing happen, and give up. - It can publish straight away. If the sender’s address belongs to a user who can publish, the post goes live immediately. Otherwise it’s saved as Pending, with the admin as author.
- The subject becomes the title and the email body becomes the content.
- Formatting is basic. HTML emails are cut down to a few tags: paragraphs and bold survive, links, headings and lists don’t.
- It’s rate-limited to one check every 5 minutes (the
WP_MAIL_INTERVALconstant).
Make it safe for automated email
For automated or AI-written content, you want a person to check every post before it goes live, and you want the mailbox checked without anyone visiting a URL. This snippet does both:
<?php
// Everything that arrives through Settings → Writing → Post via email is saved as a draft.
add_filter(
'wp_insert_post_data',
static function ( $data ) {
if ( did_action( 'wp-mail.php' ) && 'post' === $data['post_type'] ) {
$data['post_status'] = 'draft';
}
return $data;
}
);
// Check the mailbox once an hour (WordPress never checks it by itself).
add_action(
'init',
static function () {
if ( get_option( 'mailserver_login' ) && 'mail.example.com' !== get_option( 'mailserver_url' ) && ! wp_next_scheduled( 'check_post_by_email' ) ) {
wp_schedule_event( time(), 'hourly', 'check_post_by_email' );
}
}
);
add_action(
'check_post_by_email',
static function () {
wp_remote_get( site_url( 'wp-mail.php' ), array( 'timeout' => 30 ) );
}
);
Add it to your child theme’s functions.php or a code snippets plugin, after filling in the Post via email settings.
- Every emailed post is saved as a draft, whoever sent it.
- The mailbox is checked every hour through WP-Cron. WP-Cron runs when the site gets visits. On a quiet site, or if your host blocks the site from calling itself, use a real server cron job (or a free cron service) to open
https://yoursite.com/wp-mail.phpevery hour instead.
When to use something else
If the formatting matters (links, headings, images), use Zapier or Make: “new email → create WordPress post (draft)” keeps the HTML. Jetpack’s Post by Email is a hosted alternative. For everything else, the built-in feature plus two hooks is enough, and it’s free.
Tested with
WordPress 7.1 and a test POP3 mailbox: without the snippet, mail from an admin address was published and mail from an unknown address was pending. With it, both arrived as drafts, and the hourly event fetched the mail.
In Snipfire, this is “Posts sent by email wait as drafts” in the Posts and the editor library.