Kiedy wszystko zaczyna się walić... dodanie alternatywnego routingu do Cloudflare Email Routing przy pomocy Email Workers

Zawartość

Dzięki Cloudflare Email Routing mogę odbierać i wysyłać e-maile w mojej domenie, ale nadal zarządzać nimi na moim zwykłym koncie Gmail. Wszystko jest ustawione tak jak napisałem w moim wpisie Poczta we własnej domenie z Cloudflare (i Gmail)

W zeszłym tygodniu napotkałem problem polegający na tym, że e-maile nie docierały do mojej skrzynki pocztowej.

Najpierw pomyślałem, że coś jest nie tak z usługą Gmail, która blokuje przesyłane dalej wiadomości. Niestety, to samo spotkało wielu innych osób korzystających z tej usługi czytając ich wpisy w Internecie.

Na stronie społeczności Cloudflare znajduje się wpis, w którym zaczęto narzekać na to i utratę wiadomości e-mail, szczególnie podczas korzystania z routingu poczty e-mail z Cloudflare.

Kiedy wiadomość została odrzucona po stronie Cloudflare, została zgłoszona jako Delivery Fail (Niepowodzenie dostarczenia) i opisana z następującym komunikatem:

transient error (451): 4.7.650 The mail server [104.30.8.112] has been temporarily rate limited due to IP reputation.

Jako, że nie ma możliwości podglądu wiadomości w Cloudflare ani zrobienia z nią czegokolwiek ciężko jest zdiagnozować problem.

O ile bardzo lubię Cloudflare, tak i ja, podobnie jak inni użytkownicy, zastanawialiśmy się nad rezygnacją z tego rozwiązania na rzecz bardziej niezawodnych opcji.

Wracając do komunikatu o błędzie, ponieważ myślałem, że jest to spowodowane ograniczeniem Gmaila, szybko udało mi się zmienić regułę routingu, aby przekierowywać moje e-maile na pocztę Outlook.

Zwykle serwery poczty e-mail, które nie były w stanie dostarczyć wiadomości do miejsca docelowego, będą podejmować kolejne próby, zanim je odrzucą. Przekierowanie z Gmaila do Outlooka spowoduje zmianę trasy i przy kolejnej próbie dostarczenia poczta zostanie poproszona w innym kierunku (Outlook).

Zadziałało! W ciągu kilku dni otrzymałem większość e-maili, których nie udało się dostarczyć do Gmaila.

Co zaskakujące, wszystkie zostały dostarczone przez serwery Outlooka i oznaczone jako spam (śmieci), dlatego jest tu coś więcej niż tylko konflikt między Cloudflare a Gmailem.

Jednak nadszedł kolejny dzień i zobaczyłem podobny problem zgłoszony przez serwery Microsoft:

upstream (outlook-com.olc.protection.outlook.com.) temporary error: Unknown error: transient error (451): 4.7.650 The mail server [104.30.8.115] has been temporarily rate limited due to IP reputation.

To nie może być przypadek i coś musi być nie tak z Cloudflare.

Ludzie zaczynają się skarżyć, twierdząc, że Cloudflare nie jest zainteresowany naprawieniem tego problemu. Choć problem wygląda na błahy, naprawienie go może nie być tak proste, jak można sobie wyobrazić.

Ponieważ usługa jest świadczona bezpłatnie, trudno bezpośrednio poprosić o pomoc, jednak część użytkowników, którzy zdecydowali się na płatny abonament, również narzeka na brak wsparcia w tej kwestii.

Mijały dni i wydawało się, że sytuacja blokowania po stronie Gmaila powróciła do poprzedniego poziomu, w którym e-mail był blokowany, a po ponownej próbie zazwyczaj akceptowany i przekazywany po 20 minutach.

Pozostaje jednak pytanie, jak poważne konsekwencje może mieć dla nas ta zawodność i co możemy z tym zrobić.

Możliwość odbierania e-maili w mojej domenie jest dla mnie dość istotna. Z poczty e-mail w mojej domenie korzystam od lat, kiedy korzystałem z Google Workspace (w wersji darmowej) i korzystam z niej niemal wszędzie.

Niezależnie od tego, czy powoduje to jakiekolwiek straty materialne, czy nie, trudno sobie pozwolić na utratę istotnej komunikacji tylko dlatego, że niektóre adresy IP po stronie Cloudflare zostały sklasyfikowane jako spam.

Wprowadziłem środki łagodzące (tymczasowe przekierowania), ale w międzyczasie szukałem alternatywnego rozwiązania na wypadek, gdyby sytuacja się powtórzyła w przyszłości.

Jeśli jesteś pojedynczym użytkownikiem w swojej domenie, wybór innego rozwiązania na rynku (płatnego) może być proste. Jednakże, gdy zaczniesz budować liczbę użytkowników (rodziny), dodatkowe płacenie za każdego użytkownika nagle stanie się niepotrzebnie bardzo kosztowne. Już na początku warto przemyśleć wybór odpowiedniej usługi.

Mając na uwadze mój budżet, zastanowiłem się nad płatnym rozwiązaniem umożliwiającym przekazywanie wiadomości e-mail do Gmaila o nazwie Gmailify (Gmailify.com). Gmailify pobiera opłatę w wysokości 6,99 USD rocznie za domenę, niezależnie od użytkowników. Usługę, podobną w nazwie do rozwiązania Google, ale różniącą się funkcjonalnością, tworzy osoba o imieniu Mercata Sagl mieszkająca w Szwajcarii.

Autor tej usługi tworzy ją z myślą o Gmailu. Komunikacja odbywa się wyłącznie z serwerami Google i odbywa się głównie przy użyciu protokołu IPv6, w razie potrzeby powracając do protokołu IPv4. Obsługuje SPF, DMARC i DKIM w określonych domenach. W porównaniu z Cloudflare Email Routing, gdzie mogę ustawić SPF i DMARC, nie znalazłem sposobu na użycie DKIM z Gmailem i prawdopodobnie na tym właśnie polega główny problem tej usługi przesyłania dalej.

Ale czy napewno?

Cloudflare podpisuje każdy e-mail, w którym brakuje DKIM, swoim kluczem, a w raporcie widnieje informacja, że wiadomość pochodzi z email.cloudflare.com.

Ktoś w dyskusji powiedział coś, co skłoniło mnie do zastanowienia się, zanim podjąłem decyzję o zmianie usługodawcy.

„Martwię się o niezawodność i bezpieczeństwo zarówno Gmailify, jak i Forewardemail…

Obydwa rozwiązania sprawiają wrażenie 1-osobowych firmy, które wyrosły z hobby. Co zwykle jest świetne w przypadku projektów OSS, ale w przypadku podstawowej i krytycznej usługi, takiej jak poczta e-mail dla całych domen, nie wiem… Kto wie, czy ich infrastruktura nie mogłaby się załamać pod wpływem ataku, czy też nie mogłaby stać się wektorem ataku dla kogoś, kto przechwyci kody 2FA w wiadomościach e-mail, itd. Niezastąpiony człowiek może wyjechać na wakacje lub umrzeć…”

Cloudflare Radar Malicious Emails

W ramach korzystania z innych usług Cloudflare sprawdzałem ich radar Cloudflare i wykres dla Email Security. W weekend, kiedy problem osiągnął szczyt, okazało się, że 50% e-maili na całym świecie zostało sklasyfikowanych jako potencjalne zagrożenie. Zbieg okoliczności?

Łatwo jest wyciągnąć pochopne wnioski i zacząć wypowiadać się źle na temat usługi świadczonej bezpłatnie. Oczywiście jest miejsce na ulepszenia, ale jeśli na horyzoncie wydarzy się coś większego, czego nikt nie rozumie, pierwszą linią obrony będą praktyki łagodzące i cierpliwość.

Dyskusja, która toczyła się w społeczności, stała się przez część osób tyradą na temat Cloudflare (obecnie usuniętego przez tę osobę). Tyrada pełna żądań usługi, która jest świadczona taką jaka jest, bez żadnych opłat i zobowiązań. Niektórzy o tym zapominają.

Cloudflare Email Routing z Email Workers - Podejście 1

Uwaga spoiler: Podejście 3 jest tym, które osobiście używam.

Dyskusja jest świetna, gdy dochodzi do wniosku, który pomaga wszystkim, i ten dotarł.

Jeden z użytkowników przypomniał w swoim innym poście, że istnieje to opcja, która umożliwia doładowanie routingu poczty e-mail w Cloudflare przy pomocy Email Workers.

export default {
  async email(message, env, ctx) {

  //alias lists using RegEx. Examples below will allow for plus-addressing and subdomain addressing.
  // (I have configured wildcard (*) DNS records to catch all sub-domains). 
    const user1_alias = [
      "user1+.*@mydomain.net",
      ".*@user1.mydomain.net",      
      ];

    const user2_alias = [
      "user2+.*@mydomain.net",
      ".*@user2.mydomain.net",      
      ];

  //primary emails
    const user1_primary = 'user1@gmail.com';  
    const user2_primary = 'user2@gmail.com';  
    const user3_primary = 'user3@gmail.com';  

  //backup emails (still going to primary email, but via improvmx instead of directly from Cloudflare).
  //you will need to create a subdomain (ex. 'imx') setup using improvmx, and improvmx aliases pointed to primary email
    const user1_backup = 'user1@imx.mydomain.net';  
    const user2_backup = 'user2@imx.mydomain.net';   
    const user3_backup = 'user3@imx.mydomain.net';  
  
  //final catchall if primary and backup fails
    const user3_outlook = 'user1@outlook.com';  

  //This tests alias against message "To:", showing the value of [true] if matching.
    const is_user1_alias = RegExp(user1_alias.join("|"), "i").test(message.to);
    const is_user2_alias = RegExp(user2_alias.join("|"), "i").test(message.to);
  
  //action to take 
    //inside Try is to route to backup (ImprovMX to Gmail) to get by Cloudflare to Gmail issues.
    //outside Try is to route to Outlook (final catchall) if both primary and backup fails.
    var gmail_error;
    try {
      switch (true){
        case (is_user1_alias):
          try {await message.forward(user1_primary);}
          catch(gmail_error) {await message.forward(user1_backup);}
          break;
        case (is_user2_alias):
          try {await message.forward(user2_primary);}
          catch(gmail_error) {await message.forward(user2_backup);}
          break;
        default:
          try {await message.forward(user3_primary);}
          catch(gmail_error) {await message.forward(user3_backup);}
          break;
      }
     }
    catch(improvmx_error){
      try {await message.forward(user3_outlook);}
      catch(outlook_error) {
        message.setReject(outlook_error.message);
        return message.setReject(outlook_error.message + '\n' + improvmx_error.message + '\n' + gmail_error.message);
        }
    }
  }
}

Zapisuję to i poniższe kody dla moich referencji na wypadek, gdyby zniknęły z wątku społeczności.

Autor ustawił pracowników (Workers) poczty e-mail tak, aby wszelkie e-maile, które nie zostały dostarczone za pośrednictwem usługi Cloudflare, zostały dostarczone za pomocą innej usługi przesyłania dalej, ImprovMX.

Ustawił on poddomenę w swojej domenie głównej jako usługę e-mail na ImprovMX, gdzie domena główna nadal była zarządzana przez Cloudflare.

Dodatkowo Worker dodał możliwość przechwytywania i dostarczania wiadomości e-mail do innych subdomen, co nie jest możliwe bezpośrednio poprzez Cloudflare Email Routing, a także wprowadził możliwość przechwytywania wiadomości e-mail zawierających symbole + w adresach e-mail, które w środowisku Gmail są służy do kategoryzowania wiadomości e-mail.

Cloudflare Email Routing z Email Workers - Podejście 2

Inny użytkownik w tym samym wątku utworzył kolejny singiel pracownik poczty elektronicznej do obsługi wiadomości e-mail poprzez zastosowanie techniki catch-all.

export default {
    async email(message, env, ctx) {

        // defining all alias to user mappings we have
        const users = [{
            alias: [
                "first@firstdomain.de",
                "first@seconddomain.de",
            ],
            primary: "first@gmail.com",
            backup: "first@gmx.de",
        }, {
            alias: [
                "second@firstdomain.de",
            ],
            primary: "second@gmail.com",
            backup: "second@gmx.de",
        }, {
            alias: [
                "third_alias1@firstdomain.de",
                "third_alias2@firstdomain.de",
            ],
            primary: "third@gmail.com",
            backup: "third@gmx.de",
        }, {
            alias: [
                "fourth@firstdomain.de",
            ],
            primary: "fourth@gmail.com",
            backup: "fourth@gmx.de",
        }, ]

        // setting the target_user as our catch all user
        let target_user = {
            primary: "catchall@gmail.com",
            backup: "catchall@gmx.de",
        }

        // checking if we have a user matching and overwrite the target_user with it
        users.forEach(user => {
            if (RegExp(user.alias.join("|"), "i").test(message.to)) {
                target_user = user;
            }
        });

        // sending mail out, first to google and on error to gmx
        let reject_reason;
        try {
            await message.forward(target_user.primary);
        } catch (gmail_error) {
            reject_reason = gmail_error.message;
            try {
                await message.forward(target_user.backup);
            } catch (gmx_error) {
                reject_reason = gmx_error.message + "\n" + reject_reason;
                message.setReject(reject_reason);
            }
        }
    }
}

Obydwa rozwiązania świetnie sprawdzają się jako dodanie możliwości utworzenia trasy zapasowej, jeśli z jakiegoś powodu wiadomości e-mail zostaną odrzucone.

 <script async delay="https://dariusz.wieckiewicz.org/g/serve.js?client=ca-pub-5380116874441486"
      crossorigin="anonymous"></script>
 <ins class="adsbygoogle"
      style="display:block; text-align:center;"
      data-ad-layout="in-article"
      data-ad-format="fluid"
      data-ad-client="ca-pub-5380116874441486"
      data-ad-slot="9220966978"></ins>
 <script>
      (adsbygoogle = window.adsbygoogle || []).push({});
 </script>

Cloudflare Email Routing z Email Workers - Podejście 3

Wracając do głównego wątku w społeczności Cloudflare inny użytkownik dodał bardzo uproszczony kod dla pracownika (Worker) poczty e-mail, który wykorzystuje proste podejście do trasy zapasowej.

export default {
  async email(message, env, ctx) {
    await message.forward("your gmail address").catch((err) => {
      return message.forward("your alternative mailbox address");
    });
  }
}

Myślałem o zastosowaniu bardziej złożonego podejścia (1 lub 2), ale ostatecznie wybrałem uproszczone, ponieważ po prostu działa.

Uproszczone podejście w praktyce

Poprzez Email > Email Routing > Destination Addresses dodałem (i zweryfikowałem) adresy Gmail wszystkich użytkowników, których używam, a także ich alternatywne adresy e-mail (Outlook).

Musisz dodać i zweryfikować wszystkie trasy, które określisz w swoim Email Worker. W przeciwnym razie Worker po prostu nie dostarczy wiadomości.

Następnie utworzyłem kilka Email Workers dla każdego użytkownika i każdego scenariusza.

W Routing rules zmieniłem każdą akcję dla każdego adresu niestandardowego z Send to an email na Send to a Worker i określonego pracownika (Worker).

W ten sposób wykorzystałem proste zasady, które brzmią następująco.

Każdy, kto wyśle wiadomość e-mail na mój główny adres dariusz@ (w mojej domenie) zostanie przekierowany na mój adres @gmail.com. Jeśli z jakiegoś powodu Cloudflare zgłosi błąd w przekazywaniu, spróbuje przekierować do @outlook.com.

Przy odrobinie majsterkowania możliwe jest ustawienie podejścia 3-kierunkowego, gdy pierwsze dwa zawiodą, zostanie wypróbowany trzeci i ostatni adres. Początkowo rozważano to w podejściu 1. W przypadku większości ludzi pojedyncza trasa zapasowa powinna spełnić swoje zadanie.

Pomyślnie przesłane (przez Email Worker) e-maile zostaną oznaczone w Cloudflare, w dzienniku aktywności jako Dropped (Porzucone). Jeśli obie trasy zawiodą, wyświetli się błąd i zostanie oznaczony jako Delivery Failed (Dostarczenie nieudane).

Cloudflare Email Routing summary (March 2024)

Pomyślnie przesłane e-maile bez Email Workers zostały oznaczone jako Forwarded (Przekazane) w dzienniku aktywności i jako Dropped (Porzucone) z Email Workers. Może to być nieco mylące, ale jak słusznie zauważyła jedna osoba na forum społeczności, jest to po prostu kwestia nazewnictwa autorstwa Cloudflare. Musimy tylko ponownie przemyśleć słowo Dropped (Porzucone), ponieważ poczta została pomyślnie porzucona do skrzynki pocztowej. Cieszę się z tej interpretacji :)

Zarządzanie trasą główną i zapasową w jednym miejscu - Google Gmailify

Kiedy masz ładnie ustawiony adres główny (w Gmailu) wraz z kopią zapasową (w Outlooku), miło będzie mieć całą pocztę w jednym miejscu.

W środowisku Outlook możemy łatwo ustawić regułę przekazywania, dzięki czemu każdy e-mail, który trafi do skrzynki odbiorczej, zostanie przekazany, tym razem przez serwery Microsoft, z powrotem na nasz główny adres Gmail.

Testowałem i działa dobrze, ale…

Jest jeden problem z samym włączeniem przekazywania w Outlooku.

Tylko e-maile, które pomyślnie trafiły do skrzynki odbiorczej, są przekazywane dalej. Jeśli którykolwiek z naszych e-maili zostanie przekazany przez Cloudflare na alternatywny adres e-mail, wyląduje w folderze Śmieci, pozostanie tam (tylko przez 10 dni, zgodnie z polityką przechowywania Outlook).

Nie widzę siebie, jak od czasu do czasu wchodzę do Outlooka tylko po to, żeby sprawdzić folder Śmieci, dlatego skorzystałem z Gmailify, aby mi w tym pomóc.

Wspomniałem na początku o Gmailify, ale tym razem mam na myśli Gmailify, usługę oferowaną przez Google. Wiem, to mylące!

Ze względu na tę samą nazwę dla dwóch różnych usług świadczonych przez dwóch różnych autorów, dlatego twórca Gmailify.com umieścił to na swojej stronie internetowej:

To nie Gmailify Google

Gmail ma funkcję o nazwie Gmailify. Służy jednak innemu celowi, łącząc konta Outlook i Yahoo z Gmailem. Nasza usługa łączymy Gmaila z domenami. Konflikt nazw jest przypadkowy.

Gmailify od Google pozwala dodać Twoje konto Outlook w tak unikalny sposób, że nie będzie po prostu pobierać wiadomości z innego e-maila, tak jak ma to miejsce przy ustawieniu go przez protokół POP3 lub IMAP. Gmailify zintegruje pocztę Outlook z Twoim środowiskiem Gmail.

Jeśli coś wyląduje w folderze Śmieci w programie Outlook po synchronizacji w środowisku Gmail (nie jest to natychmiastowe), zobaczysz tę wiadomość w folderze Śmieci w Gmailu. Świetnie!

Jeśli usuniesz wiadomość z folderu Śmieci po stronie Gmaila, zostanie ona również usunięta z Outlooka.

Dzięki przekierowaniu ustawionemu w Outlooku dla wszystkich wiadomości przychodzących i Gmailify by Google, możesz zarządzać swoją główną pocztą e-mail i zapasową z jednego miejsca, Gmaila.

Inne podejście

Wraz z wprowadzeniem prostego routingu z Cloudflare Email Workers zadałem sobie pytanie, czy możliwe jest routing na więcej niż jeden adres e-mail?

W innym poście w społeczności znalazłem prostą odpowiedź na pytanie, jak to osiągnąć.

export default {
  async email(message, env, ctx) {
    const forwardList = ["email1@gmail.com", "email2@gmail.com"];
    for(const email of forwardList){
      await message.forward(email);
    }
  }
}

Przy odrobinie majsterkowania Worker może stać się ciekawą metodą realizacji celu, o który od jakiegoś czasu pytają użytkownicy Cloudflare, czyli kierowania poczty e-mail na więcej niż jeden adres z tego samego użytkownika.

Nie jestem ekspertem, ale z grubsza pomysł będzie taki:

export default {
  async email(message, env, ctx) {
    const forwardList = ["email1@gmail.com", "email2@gmail.com"];
    for(const email of forwardList){
      await message.forward(email).catch((err) => {
      return message.forward("email@outlook.com");
    });
    }
  }
}

Z wieloma kopiami zapasowymi:

export default {
  async email(message, env, ctx) {
    const forwardList = ["email1@gmail.com", "email2@gmail.com"];
    const backupList = ["email1@outlook.com", "email2@outlook.com"];
    for(const email of forwardList,backup of backupList){
      await message.forward(email).catch((err) => {
      return message.forward(backup);
    });
    }
  }
}

Nie mogę zagwarantować, że to zadziała, ponieważ może to mieć pewne negatywne skutki, jeśli jeden e-mail zakończy się niepowodzeniem, a inny nie.

Osobiście korzystam z trasy e-mail Cloudflare z mojej domeny na prywatny adres e-mail Grupy Google, z którego przekazuję wiadomości do wielu użytkowników.


Ostatnie słowo w tym poście to liczba wykorzystanych zapytań do Workers w Cloudflare.

W ramach naszego konta mamy limit bezpłatnych kont wynoszący 100 000 żądań dziennie. Interesujące jest to, że kiedy ustawiam reguły, po przesłaniu około 50 e-maili liczba żądań zbliża się do 600. Nie jestem pewien, jak dokładnie liczone są żądania pracowników, ale myślę, że zmieszczę się w limicie na mój prywatny użytek.

Pozdrowienia.

Komentarze
Kategorie