{"id":19501266,"url":"https://github.com/acryps/mail","last_synced_at":"2026-05-07T16:37:40.416Z","repository":{"id":198476086,"uuid":"664565487","full_name":"acryps/mail","owner":"acryps","description":"Basic tsx mailer","archived":false,"fork":false,"pushed_at":"2023-07-31T08:25:44.000Z","size":22,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-01-08T10:14:36.778Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/acryps.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2023-07-10T09:02:42.000Z","updated_at":"2023-10-05T12:53:57.000Z","dependencies_parsed_at":null,"dependency_job_id":"f30148f0-a26a-44f9-9328-c1502c274da1","html_url":"https://github.com/acryps/mail","commit_stats":null,"previous_names":["acryps/mail"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acryps%2Fmail","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acryps%2Fmail/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acryps%2Fmail/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acryps%2Fmail/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/acryps","download_url":"https://codeload.github.com/acryps/mail/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240749050,"owners_count":19851395,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-10T22:12:03.831Z","updated_at":"2026-05-07T16:37:35.388Z","avatar_url":"https://github.com/acryps.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# acryps mail\nComponent based queued mail handler\n\n\u003e This package uses [nodemailer](https://npmjs.com/nodemailer).\n\nWhen initializing a mailer you have to define a bunch of things right away.\n\nMail | TStoredMail, TStoredAddress\n:-- | :--\nSender address | Email address to send from\nTransport configuration | Nodemailer config for the mail transporter (It has no typings because nodemailer doesn't provide them in the first place)\nConvert to sendable mail | Convert TStoredMail into a sendable mail\nCreate | Create TStoredMail and TStoredAddresses\nMark as sent | Mark TStoredMail as sent\nUnsent queue | Optional initial unsent TStoredMail queue (fetch from db)\n\n\nThese are the minimum requirements for a functional mailer.\nOptionally DKIM can be added to sign the mails in the headers and send error can be handled.\n\nThe mailer also supports localization via polyfills. Defining `\u003cdiv\u003e{'Hello'.german('Hallo')}\u003c/div\u003e` in the component automatically translates according to the preferred language passed in the send method.\nCurrently only german translation is supported and the tag to pass into the send method is hardcoded to `de`. This obviously isn't convenient and will be fixed soon.\n\n## Example usage:\n### Setup Mailer\n```\nconst mailer = new Mailer\u003cMail, Address\u003e(\n\t'example@domain.com', \n\n\t// Transport configuration\n\t{\n\t\thost: 'smtp.host.com',\n\t\tport: 587,\n\t\tsecure: false,\n\t\tauth: {\n\t\t\tuser: 'example@domain.com',\n\t\t\tpass: 'securepassword1234'\n\t\t},\n\t\ttls: {\n\t\t\trejectUnauthorized: false\n\t\t}\n\t}, \n\n\t// Convert to sendable mail\n\tasync model =\u003e {\n\t\tconst recipients: string[] = await getRecipientEmails(model);\n\n\t\treturn {\n\t\t\tsubject: model.subject,\n\t\t\ttext: model.text,\n\t\t\thtml: model.html,\n\t\t\trecipients\n\t\t}\n\t},\n\n\t// Create\n\tasync (addresses, mail) =\u003e {\n\t\tconst model = new Mail();\n\n\t\tmodel.created = new Date();\n\t\tmodel.subject = mail.subject;\n\t\tmodel.text = mail.text;\n\t\tmodel.html = mail.html;\n\n\t\tawait model.create();\n\n\t\tfor (const address of addresses) {\n\t\t\tconst mailAddress = new MailAddress();\n\n\t\t\tmailAddress.address = address;\n\t\t\tmailAddress.mail = model;\n\n\t\t\tawait mailAddress.create();\n\t\t}\n\n\t\treturn model;\n\t},\n\t\n\t// Mark as sent\n\tasync model =\u003e {\n\t\tmodel.sent = new Date();\n\t\n\t\tawait model.update();\n\t},\n\n\t// Unsent queue\n\tawait db.mail.where(mail =\u003e mail.sent == null).toArray()\n);\n\nmailer.addDKIM(process.env.MAIL_DOMAIN, process.env.MAIL_DKIM_KEY);\nmailer.onSendError = async (model, mail, error) =\u003e console.log(`Mail from ${mailer.sender} to ${mail.recipients} failed to send (id: ${model.id}):`, error);\n```\n\n### Creating Mail Component\n```\nexport class ExampleMail extends MailComponent {\n\tconstructor(\n\t\tprivate fullname: string\n\t) {}\n\n\trender(child?: MailComponent): MailNode {\n\t\treturn \u003chtml\u003e\n\t\t\t\u003chead\u003e\n\t\t\t\t\u003cmeta charset=\"UTF-8\" /\u003e\n\t\t\t\t\u003cmeta name=\"viewport\" content=\"width=device-width,initial-scale=1\" /\u003e\n\t\t\t\t\u003cmeta name=\"x-apple-disable-message-reformatting\" /\u003e\n\t\t\t\u003c/head\u003e\n\t\t\t\u003chead\u003e\n\t\t\t\t\u003cstyle\u003e...\u003c/style\u003e\n\t\t\t\u003c/head\u003e\n\t\t\t\u003cbody\u003e\n\t\t\t\t\u003cdiv class=\"line\"\u003eHello {this.fullname}\u003c/div\u003e\n\n\t\t\t\t{child}\n\n\t\t\t\t\u003cdiv class=\"line\"\u003eGreetings\u003c/div\u003e\n\n\t\t\t\t\u003cdiv class=\"address\"\u003e\n\t\t\t\t\t\u003cdiv class=\"address-line\"\u003eName\u003c/div\u003e\n\t\t\t\t\t\u003cdiv class=\"address-line\"\u003eStreet\u003c/div\u003e\n\t\t\t\t\t\u003cdiv class=\"address-line\"\u003ePlace City\u003c/div\u003e\n\t\t\t\t\u003c/div\u003e\n\n\t\t\t\t\u003ca href=\"mailto:example@domain.com\"\u003eexample@domain.com\u003c/a\u003e\n\t\t\t\u003c/body\u003e\n\t\t\t\u003c/html\u003e;\n\t}\n}\n```\n\n### Sending Mail\n```\n// The passed address is of type TStoredAddress defined previously for the mailer.\nmailer.send(new ExampleMail('Foo Bar'), address, 'de');\n```\n\n## Sponsoring and support\nThis project is sponsored and supported by [ACRYPS](https://acryps.com).","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Facryps%2Fmail","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Facryps%2Fmail","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Facryps%2Fmail/lists"}