cloudflare-docs icon indicating copy to clipboard operation
cloudflare-docs copied to clipboard

Better docs for Email Workers

Open acoyfellow opened this issue 1 year ago • 1 comments

Which Cloudflare product(s) does this pertain to?

Email Routing, Workers

Subject Matter

Better examples, better error documentation

Content Location

https://developers.cloudflare.com/email-routing/email-workers/reply-email-workers/

Additional information

Please give:

  • Examples we can copy and paste (the current one relies on a fictional createTicket() function)
  • Example errors we can debug from (since the logging experience is a nightmare)

I have a simple "hello world" that 1/2 works (set-up as a wildcard catchall):

import { EmailMessage } from "cloudflare:email";
import { createMimeMessage } from "mimetext";

export default {
  async email(message, env, ctx) {
    const incomingMessageId = message.headers.get("Message-Id");
    const incomingReferences = message.headers.get("References") || '';
    const subject = message.headers.get("Subject");
    const msg = createMimeMessage();
    msg.setHeader("In-Reply-To", incomingMessageId);
    const updatedReferences = `${incomingReferences} ${incomingMessageId}`.trim();
    msg.setHeader("References", updatedReferences);
    msg.setSender({ addr: message.to });
    msg.setRecipient(message.from);
    msg.setSubject(`Re: ${subject}`);
    msg.addMessage({
      contentType: 'text/plain',
      data: `🐶 Hello! We have received your message (${new Date().toString()}).`
    });
    const replyMessage = new EmailMessage(
      message.to,
      message.from,
      msg.asRaw()
    );

    await message.reply(replyMessage);
  }
}

  • I can send an email to this catch-all worker, and it replies the first time.
  • When i reply to the reply (a "nested reply"), the error gets thrown: "original email is not repliable" with absolutely no context, or more information on how to debug.
  • I've tried all different variations, like not setting the References header, trying different formats.. It's like this header is not being read right by Cloudflare or something
{
  "outcome": "exception",
  "scriptName": "**redacted**",
  "diagnosticsChannelEvents": [],
  "exceptions": [
    {
      "name": "Error",
      "message": "original email is not repliable",
      "timestamp": 1706802189551
    }
  ],
  "logs": [],
  "eventTimestamp": 1706802189512,
  "event": {
    "rawSize": 7445,
    "rcptTo": "**redacted**",
    "mailFrom": "**redacted**"
  },
  "id": 1
}

acoyfellow avatar Feb 01 '24 15:02 acoyfellow

Surprised i'm the only concerned citizen here.. This is what's preventing me from building an email bot. Is that not a main use case for email workers?

Edit: @deadlypants1973 is it possible to at least acknowledge this, so i can plan accordingly?

acoyfellow avatar Feb 20 '24 20:02 acoyfellow

I'm baffled I can't get a response on this topic anywhere. Going on weeks of absolutely no response from official support ticket with Cloudflare, either.

@deadlypants1973 can we at least acklowgedge this issue?

acoyfellow avatar Mar 11 '24 16:03 acoyfellow

Hey @acoyfellow. We don't allow replying to what we already consider to be a reply, this is to prevent reply loops.

In essence an email cannot be replied to when:

  • has X-Auto-Response-Suppress header with value != "none"
  • has In-Reply-To header
  • has Auto-Submitted with value != "no"

Hope this clears things up.

edevil avatar Mar 15 '24 09:03 edevil

@edevil thank you for the response.

Is that anywhere in the docs? That would have been hugely helpful to see last month.

acoyfellow avatar Mar 15 '24 10:03 acoyfellow

I looked at https://developers.cloudflare.com/email-routing/email-workers/reply-email-workers/ and couldn't find this particular information, so I'm guessing the other internal conditions are not metpart alludes to this.

edevil avatar Mar 15 '24 11:03 edevil

Ok, well I think that listing out those internal conditions would be an ideal addition to those docs.

acoyfellow avatar Mar 15 '24 11:03 acoyfellow

I still can't get past this issue..

// Ensure these headers comply with Cloudflare's requirements for a message to be reply-able.
msg.setHeader("Auto-Submitted", "no");
msg.setHeader("X-Auto-Response-Suppress", "none");

Seems to have no effect, or there are other internal limitations

acoyfellow avatar Mar 17 '24 17:03 acoyfellow

So I did just find this:

https://developers.cloudflare.com/email-routing/postmaster/#sending-or-replying-to-an-email-from-your-cloudflare-domain

Email Routing does not support sending or replying from your Cloudflare domain. When you reply to emails forwarded by Email Routing, the reply will be sent from your destination address (like [email protected]), not your custom address (like [email protected]).

So.. This sounds like what I'm trying to accomplish is just not allowed / not a feature of Email Workers at this point, even though I got some conflicting info from Discord

I was able to build a "hello world email bot" by utilzing a third party email server like mailgun. It's unfortunate we can't open up the use cases here, I guess that would be too good to be true. I love workers.

const YOUR_MAILGUN_DOMAIN = `inbox.dog`;
const MAILGUN_API_KEY = ``;
const from = `Inbox Dog <hello@${YOUR_MAILGUN_DOMAIN}>`;

export default {
  async email(message) {
    const originalMessageId = message.headers.get('Message-ID');
    const mailgunUrl = `https://api.mailgun.net/v3/${YOUR_MAILGUN_DOMAIN}/messages`;
    const formData = new URLSearchParams();
    formData.append('from', from);
    formData.append('to', message.from);
    formData.append('h:In-Reply-To', originalMessageId);
    formData.append('subject',
      `Re: ${message.headers.get('Subject')}`
    );
    formData.append('text',
      `🐶 Hello again! Following up on our conversation (${new Date().toString()}).`
    );
    const response = await fetch(mailgunUrl, {
      method: 'POST',
      headers: {
        Authorization: `Basic ${btoa(`api:${MAILGUN_API_KEY}`)}`,
        'Content-Type': 'application/x-www-form-urlencoded',
      },
      body: formData,
    });
    if (response.ok) {
      console.log('Reply sent successfully');
    } else {
      console.log('Failed to send reply');
    };
  }
};

acoyfellow avatar Mar 17 '24 20:03 acoyfellow

I still can't get past this issue..

// Ensure these headers comply with Cloudflare's requirements for a message to be reply-able.
msg.setHeader("Auto-Submitted", "no");
msg.setHeader("X-Auto-Response-Suppress", "none");

Seems to have no effect, or there are other internal limitations

These conditions are relative to the email you are trying to reply to, not the one you are sending.

edevil avatar Mar 18 '24 10:03 edevil

So I did just find this:

https://developers.cloudflare.com/email-routing/postmaster/#sending-or-replying-to-an-email-from-your-cloudflare-domain

Email Routing does not support sending or replying from your Cloudflare domain. When you reply to emails forwarded by Email Routing, the reply will be sent from your destination address (like [email protected]), not your custom address (like [email protected]).

You can definitely reply to emails from your Cloudflare domain using a worker, provided the conditions stated above are true. That part of the documentation predates the "Replying from workers" functionality.

edevil avatar Mar 18 '24 10:03 edevil

Would you be able to provide an example of what I'm trying to accomplish then?

I want to see how to reply to a reply, a nested reply.

  1. [email protected] sends email to Worker.
  2. Worker replies.
  3. Person replies back.
  4. Worker replies to that reply.

acoyfellow avatar Mar 18 '24 10:03 acoyfellow

You cannot reply to a reply. As I stated also above we actively prevent you from replying to what we consider is already a reply, this is to prevent reply loops.

edevil avatar Mar 18 '24 10:03 edevil

That's what my conclusion was - I'm sure my wording and understanding has made this confusing.

Thanks for the clarity @edevil, that's what I consider to be "too bad". I would love to be able to create a bot that can handle back-and-forth dialog with just workers.

acoyfellow avatar Mar 18 '24 11:03 acoyfellow