[{"data":1,"prerenderedAt":940},["ShallowReactive",2],{"navigation_docs":3,"-proxy":32,"-proxy-surround":937},[4,8,12,16,20,24,28],{"title":5,"path":6,"stem":7},"Set up your server","\u002Fsetup","1.setup",{"title":9,"path":10,"stem":11},"Addresses and domains","\u002Faddresses","2.addresses",{"title":13,"path":14,"stem":15},"Sign-in and discovery","\u002Fsign-in","3.sign-in",{"title":17,"path":18,"stem":19},"Mail apps","\u002Fproxy","4.proxy",{"title":21,"path":22,"stem":23},"Spam","\u002Fspam","5.spam",{"title":25,"path":26,"stem":27},"Configuration","\u002Fconfiguration","6.configuration",{"title":29,"path":30,"stem":31},"Troubleshooting","\u002Ftroubleshooting","7.troubleshooting",{"id":33,"title":34,"body":35,"description":291,"extension":930,"links":931,"meta":932,"navigation":933,"path":18,"seo":934,"stem":19,"__hash__":936},"docs\u002F4.proxy.md","Mail apps and the IMAP proxy",{"type":36,"value":37,"toc":910},"minimark",[38,47,54,59,122,125,128,141,144,158,162,165,190,197,200,211,226,229,233,244,249,263,267,278,282,285,301,310,316,386,531,538,542,551,560,563,572,575,579,590,627,634,638,647,657,666,675,684,688,697,701,704,763,766,770,800,804,830,834,866,870,873,896,899,903,906],[39,40,41,42,46],"p",{},"Mailopus speaks JMAP. Apple Mail, iOS Mail, Thunderbird and Outlook speak IMAP and SMTP. The proxy in ",[43,44,45],"code",{},"imap\u002F"," sits between them. Clients connect to it on the usual ports, and it talks JMAP over HTTPS to your Worker. It keeps no database. Mail, flags and IMAP UIDs all live in Mailopus, so you can rebuild or move the proxy at any time.",[39,48,49,50,53],{},"Workers can't accept raw TCP connections, so the proxy has to run on a machine you control. Each proxy talks to exactly one Mailopus server, set by ",[43,51,52],{},"MAILOPUS_URL",". The one at imap.mailopus.net talks to app.mailopus.net's own server, so it can't reach yours, and routing your mail through it would put your password and mail on a machine Larry runs. Run your own copy.",[55,56,58],"h2",{"id":57},"what-it-supports","What it supports",[60,61,62,78],"table",{},[63,64,65],"thead",{},[66,67,68,72,75],"tr",{},[69,70,71],"th",{},"Protocol",[69,73,74],{},"Port",[69,76,77],{},"Security",[79,80,81,93,103,113],"tbody",{},[66,82,83,87,90],{},[84,85,86],"td",{},"IMAP",[84,88,89],{},"993",[84,91,92],{},"SSL\u002FTLS",[66,94,95,97,100],{},[84,96,86],{},[84,98,99],{},"143",[84,101,102],{},"STARTTLS",[66,104,105,108,111],{},[84,106,107],{},"SMTP submission",[84,109,110],{},"465",[84,112,92],{},[66,114,115,117,120],{},[84,116,107],{},[84,118,119],{},"587",[84,121,102],{},[39,123,124],{},"On the plain ports, sign-in stays off until STARTTLS is up.",[39,126,127],{},"Not there yet:",[129,130,131,135,138],"ul",{},[132,133,134],"li",{},"CONDSTORE. Clients resync flags without it, which costs more traffic on big mailboxes.",[132,136,137],{},"Creating, renaming or deleting folders from a mail app. The proxy refuses all three. Mailopus can rename and delete labels over JMAP, but the proxy doesn't pass that through, and no one can create a folder yet.",[132,139,140],{},"SENTSINCE and SENTBEFORE searches use the received date, not the Date header.",[39,142,143],{},"Limits:",[129,145,146,149,152,155],{},[132,147,148],{},"Messages up to 25 MiB, the same as Email Routing.",[132,150,151],{},"50 recipients per message.",[132,153,154],{},"20 connections per IP.",[132,156,157],{},"5 failed sign-ins in 15 minutes lock that IP out for 15 minutes. Your Worker separately allows 20 failed app-password attempts a minute per username.",[55,159,161],{"id":160},"app-passwords","App passwords",[39,163,164],{},"Each mail app signs in with its own app password, made in Settings > Account > App passwords. The username is your email address.",[166,167,168,171,183],"ol",{},[132,169,170],{},"Type a name, such as \"iPhone Mail\".",[132,172,173,174,178,179,182],{},"Pick which mail it can see. ",[175,176,177],"strong",{},"All mail",", or ",[175,180,181],{},"Only"," one address or one address group.",[132,184,185,186,189],{},"Press ",[175,187,188],{},"Create"," and copy the password. It's 32 letters and digits, and Settings shows it only once.",[39,191,192,193,196],{},"One app password per app means you can revoke one without touching the others. The list shows when each was made and last used, and ",[175,194,195],{},"Revoke"," stops it at once. A revoked password can keep working for up to a minute on a Worker instance that cached it.",[39,198,199],{},"A password limited to some addresses:",[129,201,202,205,208],{},[132,203,204],{},"sees only mail sent to those addresses",[132,206,207],{},"sends only as identities among them",[132,209,210],{},"can't change folders or identities",[39,212,213,214,217,218,221,222,225],{},"App passwords work on the JMAP paths only, ",[43,215,216],{},"\u002Fjmap\u002F*"," and ",[43,219,220],{},"\u002F.well-known\u002Fjmap",". They can't reach ",[43,223,224],{},"\u002Fapi\u002F*",", so they can't make or revoke app passwords or touch passkeys.",[39,227,228],{},"The username can be any address the account sends as or receives, including one at a catch-all domain.",[55,230,232],{"id":231},"run-the-proxy","Run the proxy",[39,234,235,236,243],{},"You need a small Linux server with a public IPv4 address, Docker, and DNS names for it. A 1 GB VPS is plenty. The proxy's container is capped at 256 MB. ",[237,238,242],"a",{"href":239,"rel":240},"https:\u002F\u002Fgithub.com\u002Fmailopus\u002Fserver\u002Fblob\u002Fmain\u002Fimap\u002Fdeploy\u002Fcloud.md",[241],"nofollow","imap\u002Fdeploy\u002Fcloud.md"," compares DigitalOcean and AWS.",[245,246,248],"h3",{"id":247},"_1-dns","1. DNS",[39,250,251,252,217,255,258,259,262],{},"Add two A records, for example ",[43,253,254],{},"imap.example.com",[43,256,257],{},"smtp.example.com",", pointing at the server. Set them to ",[175,260,261],{},"DNS only",", the grey cloud. Cloudflare's proxy doesn't carry mail ports.",[245,264,266],{"id":265},"_2-a-token-for-certificates","2. A token for certificates",[39,268,269,270,273,274,277],{},"The proxy gets Let's Encrypt certificates by DNS-01 through Cloudflare. In the dashboard, under My Profile > API Tokens, create a token with ",[175,271,272],{},"Zone > DNS > Edit"," on your zone and nothing else. You'll paste it into the server's ",[43,275,276],{},".env"," in the next step. Don't commit it.",[245,279,281],{"id":280},"_3-configure","3. Configure",[39,283,284],{},"On the server:",[286,287,292],"pre",{"className":288,"code":289,"language":290,"meta":291,"style":291},"language-sh shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","git clone \u003Cyour copy of the repo> mailopus\n","sh","",[43,293,294],{"__ignoreMap":291},[295,296,299],"span",{"class":297,"line":298},"line",1,[295,300,289],{},[286,302,304],{"className":288,"code":303,"language":290,"meta":291,"style":291},"cd mailopus\u002Fimap && cp .env.example .env\n",[43,305,306],{"__ignoreMap":291},[295,307,308],{"class":297,"line":298},[295,309,303],{},[39,311,312,313,315],{},"Edit ",[43,314,276],{},". The example file points at app.mailopus.net and uses a self-signed certificate, so change these:",[286,317,319],{"className":288,"code":318,"language":290,"meta":291,"style":291},"MAILOPUS_URL=https:\u002F\u002Fmailopus.\u003Cyour subdomain>.workers.dev\nTLS_MODE=acme\nTLS_HOSTNAMES=imap.example.com,smtp.example.com\nSMTP_HOSTNAME=smtp.example.com\nCF_API_TOKEN=\u003Cthe token from step 2>\nACME_EMAIL=you@example.com\nIMAP_BIND=0.0.0.0\nIMAP_PORT=993\nIMAP_STARTTLS_PORT=143\nSMTPS_PORT=465\nSUBMISSION_PORT=587\n",[43,320,321,326,332,338,344,350,356,362,368,374,380],{"__ignoreMap":291},[295,322,323],{"class":297,"line":298},[295,324,325],{},"MAILOPUS_URL=https:\u002F\u002Fmailopus.\u003Cyour subdomain>.workers.dev\n",[295,327,329],{"class":297,"line":328},2,[295,330,331],{},"TLS_MODE=acme\n",[295,333,335],{"class":297,"line":334},3,[295,336,337],{},"TLS_HOSTNAMES=imap.example.com,smtp.example.com\n",[295,339,341],{"class":297,"line":340},4,[295,342,343],{},"SMTP_HOSTNAME=smtp.example.com\n",[295,345,347],{"class":297,"line":346},5,[295,348,349],{},"CF_API_TOKEN=\u003Cthe token from step 2>\n",[295,351,353],{"class":297,"line":352},6,[295,354,355],{},"ACME_EMAIL=you@example.com\n",[295,357,359],{"class":297,"line":358},7,[295,360,361],{},"IMAP_BIND=0.0.0.0\n",[295,363,365],{"class":297,"line":364},8,[295,366,367],{},"IMAP_PORT=993\n",[295,369,371],{"class":297,"line":370},9,[295,372,373],{},"IMAP_STARTTLS_PORT=143\n",[295,375,377],{"class":297,"line":376},10,[295,378,379],{},"SMTPS_PORT=465\n",[295,381,383],{"class":297,"line":382},11,[295,384,385],{},"SUBMISSION_PORT=587\n",[60,387,388,398],{},[63,389,390],{},[66,391,392,395],{},[69,393,394],{},"Variable",[69,396,397],{},"Meaning",[79,399,400,409,430,440,450,462,474,494,512],{},[66,401,402,406],{},[84,403,404],{},[43,405,52],{},[84,407,408],{},"Your Worker's origin. One proxy serves one Mailopus server.",[66,410,411,416],{},[84,412,413],{},[43,414,415],{},"TLS_MODE",[84,417,418,421,422,425,426,429],{},[43,419,420],{},"acme"," for Let's Encrypt, ",[43,423,424],{},"files"," for your own certificate, ",[43,427,428],{},"self-signed"," for testing",[66,431,432,437],{},[84,433,434],{},[43,435,436],{},"TLS_HOSTNAMES",[84,438,439],{},"Names on the certificate, comma-separated",[66,441,442,447],{},[84,443,444],{},[43,445,446],{},"SMTP_HOSTNAME",[84,448,449],{},"The name SMTP announces in its greeting",[66,451,452,457],{},[84,453,454],{},[43,455,456],{},"CF_API_TOKEN",[84,458,459,461],{},[43,460,420],{}," only. The DNS token.",[66,463,464,469],{},[84,465,466],{},[43,467,468],{},"ACME_EMAIL",[84,470,471,473],{},[43,472,420],{}," only, optional. Let's Encrypt's expiry notices go here.",[66,475,476,485],{},[84,477,478,481,482],{},[43,479,480],{},"TLS_CERT",", ",[43,483,484],{},"TLS_KEY",[84,486,487,489,490,493],{},[43,488,424],{}," only. Paths inside the container, for example under ",[43,491,492],{},"\u002Fdata\u002Fcerts",".",[66,495,496,501],{},[84,497,498],{},[43,499,500],{},"IMAP_BIND",[84,502,503,504,507,508,511],{},"The host address the ports listen on. ",[43,505,506],{},"127.0.0.1"," by default, so set ",[43,509,510],{},"0.0.0.0"," on a server.",[66,513,514,528],{},[84,515,516,481,519,481,522,481,525],{},[43,517,518],{},"IMAP_PORT",[43,520,521],{},"IMAP_STARTTLS_PORT",[43,523,524],{},"SMTPS_PORT",[43,526,527],{},"SUBMISSION_PORT",[84,529,530],{},"Host ports. They default to 1993, 1143, 1465 and 1587 so a laptop needs no root.",[39,532,533,534,537],{},"Certificates are kept in the ",[43,535,536],{},"certs"," Docker volume and renewed on their own.",[245,539,541],{"id":540},"_4-start-it","4. Start it",[286,543,545],{"className":288,"code":544,"language":290,"meta":291,"style":291},"docker compose up -d --build\n",[43,546,547],{"__ignoreMap":291},[295,548,549],{"class":297,"line":298},[295,550,544],{},[39,552,553,554,217,557,559],{},"Open 993, 143, 465 and 587 in the server's firewall. Docker's published ports bypass ufw, so the port list in ",[43,555,556],{},"compose.yaml",[43,558,276],{}," is what really decides.",[39,561,562],{},"Check the logs:",[286,564,566],{"className":288,"code":565,"language":290,"meta":291,"style":291},"docker compose logs --tail 100\n",[43,567,568],{"__ignoreMap":291},[295,569,570],{"class":297,"line":298},[295,571,565],{},[39,573,574],{},"They're JSON lines and never hold passwords or message content.",[245,576,578],{"id":577},"_5-show-the-hosts-in-settings","5. Show the hosts in Settings",[39,580,581,582,585,586,589],{},"Add the hostnames to ",[43,583,584],{},"vars"," in ",[43,587,588],{},"wrangler.jsonc",":",[286,591,595],{"className":592,"code":593,"language":594,"meta":291,"style":291},"language-jsonc shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\"vars\": {\n    \"APP_ORIGIN\": \"https:\u002F\u002Fapp.mailopus.net\",\n    \"RP_ID\": \"mailopus.net\",\n    \"IMAP_HOST\": \"imap.example.com\",\n    \"SMTP_HOST\": \"smtp.example.com\"\n}\n","jsonc",[43,596,597,602,607,612,617,622],{"__ignoreMap":291},[295,598,599],{"class":297,"line":298},[295,600,601],{},"\"vars\": {\n",[295,603,604],{"class":297,"line":328},[295,605,606],{},"    \"APP_ORIGIN\": \"https:\u002F\u002Fapp.mailopus.net\",\n",[295,608,609],{"class":297,"line":334},[295,610,611],{},"    \"RP_ID\": \"mailopus.net\",\n",[295,613,614],{"class":297,"line":340},[295,615,616],{},"    \"IMAP_HOST\": \"imap.example.com\",\n",[295,618,619],{"class":297,"line":346},[295,620,621],{},"    \"SMTP_HOST\": \"smtp.example.com\"\n",[295,623,624],{"class":297,"line":352},[295,625,626],{},"}\n",[39,628,629,630,633],{},"Deploy again. Settings > App passwords then shows the servers and ports next to each new password. Without ",[43,631,632],{},"IMAP_HOST",", Settings says the server has no IMAP proxy.",[245,635,637],{"id":636},"test-it-from-a-laptop-first","Test it from a laptop first",[286,639,641],{"className":288,"code":640,"language":290,"meta":291,"style":291},"cd imap && cp .env.example .env\n",[43,642,643],{"__ignoreMap":291},[295,644,645],{"class":297,"line":298},[295,646,640],{},[39,648,649,650,652,653,656],{},"Set ",[43,651,52],{}," to your Worker and leave ",[43,654,655],{},"TLS_MODE=self-signed",". Then:",[286,658,660],{"className":288,"code":659,"language":290,"meta":291,"style":291},"docker compose up --build\n",[43,661,662],{"__ignoreMap":291},[295,663,664],{"class":297,"line":298},[295,665,659],{},[286,667,669],{"className":288,"code":668,"language":290,"meta":291,"style":291},"curl -k --url imaps:\u002F\u002Flocalhost:1993\u002FINBOX -u 'sam@example.com:\u003Capp password>' -X 'STATUS INBOX (MESSAGES UNSEEN)'\n",[43,670,671],{"__ignoreMap":291},[295,672,673],{"class":297,"line":298},[295,674,668],{},[39,676,677,678,681,682,493],{},"The proxy's own tests run with ",[43,679,680],{},"go test .\u002F..."," from ",[43,683,45],{},[245,685,687],{"id":686},"update-it","Update it",[286,689,691],{"className":288,"code":690,"language":290,"meta":291,"style":291},"git pull && docker compose up -d --build\n",[43,692,693],{"__ignoreMap":291},[295,694,695],{"class":297,"line":298},[295,696,690],{},[55,698,700],{"id":699},"set-up-mail-apps","Set up mail apps",[39,702,703],{},"Every app uses the same settings:",[60,705,706,725],{},[63,707,708],{},[66,709,710,712,715,717,719,722],{},[69,711],{},[69,713,714],{},"Server",[69,716,74],{},[69,718,77],{},[69,720,721],{},"Username",[69,723,724],{},"Password",[79,726,727,746],{},[66,728,729,732,736,738,740,743],{},[84,730,731],{},"Incoming, IMAP",[84,733,734],{},[43,735,254],{},[84,737,89],{},[84,739,92],{},[84,741,742],{},"your email address",[84,744,745],{},"the app password",[66,747,748,751,755,757,759,761],{},[84,749,750],{},"Outgoing, SMTP",[84,752,753],{},[43,754,257],{},[84,756,110],{},[84,758,92],{},[84,760,742],{},[84,762,745],{},[39,764,765],{},"Port 587 with STARTTLS works for outgoing too, if a network blocks 465.",[245,767,769],{"id":768},"apple-mail-on-mac","Apple Mail on Mac",[166,771,772,778,784,793],{},[132,773,774,775,493],{},"Mail > Add Account. Pick ",[175,776,777],{},"Other Mail Account",[132,779,780,781,493],{},"Enter your name, email address and the app password. Press ",[175,782,783],{},"Sign In",[132,785,786,787,789,790,792],{},"Mail can't find the servers on its own. When it asks, set Account Type to IMAP, Incoming Mail Server to ",[43,788,254],{}," and Outgoing Mail Server to ",[43,791,257],{},", with your address as the username both times.",[132,794,795,796,799],{},"If it still fails, open Mail > Settings > Accounts, select the account, then Server Settings. Turn off ",[175,797,798],{},"Automatically manage connection settings"," for both servers and enter the ports and TLS from the table.",[245,801,803],{"id":802},"iphone-and-ipad-mail","iPhone and iPad Mail",[166,805,806,809,815,821],{},[132,807,808],{},"Settings > Apps > Mail > Mail Accounts > Add Account > Other > Add Mail Account.",[132,810,811,812,493],{},"Enter your name, address, the app password and a description. Tap ",[175,813,814],{},"Next",[132,816,817,818,820],{},"Pick ",[175,819,86],{},". Fill in the incoming and outgoing host names, with your address and the app password for both.",[132,822,823,824,826,827,493],{},"Tap ",[175,825,814],{},", then ",[175,828,829],{},"Save",[245,831,833],{"id":832},"thunderbird","Thunderbird",[166,835,836,839,845,851,857],{},[132,837,838],{},"Account Settings > Account Actions > Add Mail Account.",[132,840,841,842,493],{},"Enter your name, address and the app password. Press ",[175,843,844],{},"Configure manually",[132,846,847,848,850],{},"Incoming: IMAP, ",[43,849,254],{},", port 993, SSL\u002FTLS, Normal password.",[132,852,853,854,856],{},"Outgoing: SMTP, ",[43,855,257],{},", port 465, SSL\u002FTLS, Normal password.",[132,858,859,860,826,863,493],{},"Username for both is your email address. Press ",[175,861,862],{},"Re-test",[175,864,865],{},"Done",[245,867,869],{"id":868},"outlook","Outlook",[39,871,872],{},"The new Outlook for Windows and Outlook for Mac both add IMAP accounts:",[166,874,875,881,887,893],{},[132,876,877,878,880],{},"Add account, then type your email address. Pick ",[175,879,86],{}," when Outlook asks for the provider, or open the advanced or manual settings.",[132,882,883,884,886],{},"IMAP incoming server ",[43,885,254],{},", port 993, SSL\u002FTLS.",[132,888,889,890,892],{},"SMTP outgoing server ",[43,891,257],{},", port 465, SSL\u002FTLS.",[132,894,895],{},"Your email address as the username for both, and the app password.",[39,897,898],{},"Outlook menus move between versions. I haven't checked these steps against every one, so expect the labels to differ a little.",[245,900,902],{"id":901},"folders","Folders",[39,904,905],{},"Your mail apps see the standard mailboxes, Inbox, Drafts, Sent, Archive, Junk and Trash, plus your labels as folders. Point the app's Sent, Drafts, Junk and Trash settings at the matching folders if it doesn't pick them itself.",[907,908,909],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":291,"searchDepth":328,"depth":328,"links":911},[912,913,914,923],{"id":57,"depth":328,"text":58},{"id":160,"depth":328,"text":161},{"id":231,"depth":328,"text":232,"children":915},[916,917,918,919,920,921,922],{"id":247,"depth":334,"text":248},{"id":265,"depth":334,"text":266},{"id":280,"depth":334,"text":281},{"id":540,"depth":334,"text":541},{"id":577,"depth":334,"text":578},{"id":636,"depth":334,"text":637},{"id":686,"depth":334,"text":687},{"id":699,"depth":328,"text":700,"children":924},[925,926,927,928,929],{"id":768,"depth":334,"text":769},{"id":802,"depth":334,"text":803},{"id":832,"depth":334,"text":833},{"id":868,"depth":334,"text":869},{"id":901,"depth":334,"text":902},"md",null,{},{"title":17},{"description":935,"title":34},"Mailopus speaks JMAP. Apple Mail, iOS Mail, Thunderbird and Outlook speak IMAP and SMTP. The proxy in imap\u002F sits between them. Clients connect to it on the usual ports, and it talks JMAP over HTTPS to your Worker. It keeps no database. Mail, flags and IMAP UIDs all live in Mailopus, so you can rebuild or move the proxy at any time.","chPSHKvCqDAoXOoUFGwJ4XKZivrXul9dXVjA7Upyxlw",[938,939],{"title":13,"path":14,"stem":15,"description":291,"children":-1},{"title":21,"path":22,"stem":23,"description":291,"children":-1},1794228095132]