diff --git a/app/controllers/api/v1/domains.js b/app/controllers/api/v1/domains.js index 1d9cff77c..8b8f096f1 100644 --- a/app/controllers/api/v1/domains.js +++ b/app/controllers/api/v1/domains.js @@ -7,9 +7,16 @@ const _ = require('lodash'); const pickOriginal = require('@ladjs/pick-original'); const config = require('#config'); +const populateDomainStorage = require('#helpers/populate-domain-storage'); const toObject = require('#helpers/to-object'); const { Users, Aliases, Domains } = require('#models'); +const VIRTUAL_KEYS = [ + 'storage_used', + 'storage_used_by_aliases', + 'storage_quota' +]; + function json(domain, isList = false) { const object = toObject(Domains, domain); // map max recipients per alias @@ -47,37 +54,33 @@ function json(domain, isList = false) { }); } + // preserve virtuals added in `app/controllers/web/my-account/list-domains.js` + // - storage_used + // - storage_used_by_aliases + // - storage_quota + const virtuals = {}; + for (const key of VIRTUAL_KEYS) { + if (typeof domain[key] !== 'undefined') virtuals[key] = domain[key]; + } + return { ...pickOriginal( object, _.isFunction(domain.toObject) ? domain.toObject() : domain ), + ...virtuals, // add a helper url link: `${config.urls.web}/my-account/domains/${domain.name}` }; } async function list(ctx) { - // hide global domain names if not admin of - // the global domain and had zero aliases - const data = ctx.state.domains - .filter((domain) => { - if (!domain.is_global) return true; - const member = domain.members.find( - (m) => m.user.id === ctx.state.user.id - ); - if (!member) return false; - if (member.group === 'admin') return true; - if (domain.has_global_aliases) return true; - return false; - }) - .map((d) => json(d, true)); - - ctx.body = data; + ctx.body = ctx.state.domains.map((d) => json(d, true)); } async function retrieve(ctx) { - const data = json(ctx.state.domain); + // populate storage quota stuff + const data = json(await populateDomainStorage(ctx.state.domain, ctx.locale)); ctx.body = data; } diff --git a/app/controllers/api/v1/emails.js b/app/controllers/api/v1/emails.js index 6da177bd4..3085e1b88 100644 --- a/app/controllers/api/v1/emails.js +++ b/app/controllers/api/v1/emails.js @@ -12,19 +12,58 @@ const config = require('#config'); const createSession = require('#helpers/create-session'); const toObject = require('#helpers/to-object'); +const REJECTED_ERROR_KEYS = [ + 'recipient', + 'responseCode', + 'response', + 'message' +]; + function json(email, isList = false) { const object = toObject(Emails, email); + + // + // NOTE: we always rewrite rejectedErrors + // since we don't want to show code bugs + // to user via API response + // + delete object.rejectedErrors; + if (isList) { + delete object.message; delete object.headers; - delete object.accepted; - delete object.rejectedErrors; + } else { + // + // instead we render it similarly as we do in My Account > Emails + // (and we only render these fields to the user) + // + // - recipient + // - responseCode + // - response + // - message + // + // (not the full error object which contains stack trace etc.) + // + object.rejectedErrors = email.rejectedErrors.map((err) => { + const error = {}; + for (const key of REJECTED_ERROR_KEYS) { + if (typeof err[key] !== 'undefined') error[key] = err[key]; + } + + return error; + }); } + // + // safeguard to always add `rejectedErrors` since + // we have it listed in omitExtraFields in emails model + // (we never want to accidentally render it to a user) + // + const keys = _.isFunction(email.toObject) ? email.toObject() : email; + if (!isList) keys.rejectedErrors = object.rejectedErrors; + return { - ...pickOriginal( - object, - _.isFunction(email.toObject) ? email.toObject() : email - ), + ...pickOriginal(object, keys), // add a helper url link: `${config.urls.web}/my-account/emails/${email.id}` }; @@ -37,7 +76,7 @@ async function list(ctx) { async function retrieve(ctx) { const body = json(ctx.state.email); // we want to return the `message` property - body.message = await Emails.getMessage(ctx.state.email.message); + body.message = await Emails.getMessage(ctx.state.email.message, true); ctx.body = body; } @@ -156,7 +195,10 @@ async function create(ctx) { ignore_hook: false }); - ctx.body = email; + // we want to return the `message` property + const body = json(email); + body.message = await Emails.getMessage(email.message, true); + ctx.body = body; } catch (err) { ctx.logger.error(err); ctx.throw(err); diff --git a/app/controllers/web/my-account/create-domain.js b/app/controllers/web/my-account/create-domain.js index efde491ba..dbb8fa55a 100644 --- a/app/controllers/web/my-account/create-domain.js +++ b/app/controllers/web/my-account/create-domain.js @@ -6,8 +6,7 @@ const Boom = require('@hapi/boom'); const { boolean } = require('boolean'); -const toObject = require('#helpers/to-object'); -const { Users, Domains, Aliases } = require('#models'); +const { Domains, Aliases } = require('#models'); const config = require('#config'); const logger = require('#helpers/logger'); @@ -94,11 +93,7 @@ async function createDomain(ctx, next) { }); } - if (ctx.api) { - ctx.state.domain = toObject(Domains, ctx.state.domain); - ctx.state.domain.members[0].user = toObject(Users, ctx.state.user); - return next(); - } + if (ctx.api) return next(); // TODO: flash messages logic in @ladjs/assets doesn't support both // custom and regular flash message yet diff --git a/app/controllers/web/my-account/list-billing.js b/app/controllers/web/my-account/list-billing.js index 47e465e89..a19264fb3 100644 --- a/app/controllers/web/my-account/list-billing.js +++ b/app/controllers/web/my-account/list-billing.js @@ -10,6 +10,7 @@ const isSANB = require('is-string-and-not-blank'); const paginate = require('koa-ctx-paginate'); const config = require('#config'); +const setPaginationHeaders = require('#helpers/set-pagination-headers'); const REGEX_AMOUNT_FORMATTED = new RE2('amount_formatted', 'i'); @@ -21,10 +22,11 @@ async function listBilling(ctx) { // sort payments let sortFn; - if (REGEX_AMOUNT_FORMATTED.test(ctx.query.sort)) - sortFn = (p) => p.amount_formatted.replace(/[^\d.]/, ''); - else if (isSANB(ctx.query.sort)) - sortFn = (p) => p[ctx.query.sort.replace(/^-/, '')]; + if (isSANB(ctx.query.sort)) { + sortFn = REGEX_AMOUNT_FORMATTED.test(ctx.query.sort) + ? (p) => p.amount_formatted.replace(/[^\d.]/, '') + : (p) => p[ctx.query.sort.replace(/^-/, '')]; + } payments = _.sortBy(payments, sortFn ? [sortFn] : ['invoice_at']); @@ -48,6 +50,18 @@ async function listBilling(ctx) { ) ); + // + // set HTTP headers for pagination + // + // + setPaginationHeaders( + ctx, + pageCount, + ctx.query.page, + payments.length, + itemCount + ); + if (ctx.accepts('html')) return ctx.render('my-account/billing', { payments, diff --git a/app/controllers/web/my-account/list-domains.js b/app/controllers/web/my-account/list-domains.js index cf8458a67..e36c39e7c 100644 --- a/app/controllers/web/my-account/list-domains.js +++ b/app/controllers/web/my-account/list-domains.js @@ -4,17 +4,38 @@ */ const _ = require('lodash'); +const dayjs = require('dayjs-with-plugins'); const isSANB = require('is-string-and-not-blank'); const paginate = require('koa-ctx-paginate'); +const pMap = require('p-map'); +const { boolean } = require('boolean'); const Aliases = require('#models/aliases'); const Domains = require('#models/domains'); const config = require('#config'); +const populateDomainStorage = require('#helpers/populate-domain-storage'); +const sendPaginationCheck = require('#helpers/send-pagination-check'); +const setPaginationHeaders = require('#helpers/set-pagination-headers'); // eslint-disable-next-line complexity -async function listDomains(ctx) { +async function listDomains(ctx, next) { let { domains } = ctx.state; + // + // starting November 1st we enforce API pagination on this endpoint + // (unless user opts in beforehand using ?pagination=true) + // + const hasPagination = dayjs().isBefore('11/1/2024', 'M/D/YYYY') + ? boolean(ctx.query.pagination) + : true; + + // + // NOTE: we send a one-time email admins that we now offer pagination + // and with notice that starting November 1st list domains/aliases + // endpoints will be paginated to 1000 results max per page by default + // + if (ctx.api && !hasPagination) await sendPaginationCheck(ctx); + // if user has ubuntu ID then check if recipient matches email address // and if so then alert the user with a flash notification if ( @@ -72,7 +93,7 @@ async function listDomains(ctx) { } // if some of the domains were not global and need setup then toast notification - if (!ctx.query.page || ctx.query.page === 1) { + if (!ctx.api && (!ctx.query.page || ctx.query.page === 1)) { // let hasSomeSetup = false; let setupRequired = false; let setupRequiredMultiple = false; @@ -161,7 +182,8 @@ async function listDomains(ctx) { }); const itemCount = domains.length; - const pageCount = Math.ceil(itemCount / ctx.query.limit); + const pageCount = + !ctx.api || hasPagination ? Math.ceil(itemCount / ctx.query.limit) : 1; // sort domains let sortFn; @@ -169,8 +191,11 @@ async function listDomains(ctx) { sortFn = (d) => d[ctx.query.sort.replace(/^-/, '')]; else { // use the default A-Z sort fn but put not verified at top, followed by mismatch + // (but the API will return default sort by `created_at` for pagination purposes) sortFn = (d) => - !d.has_mx_record || !d.has_txt_record + ctx.api + ? d.created_at + : !d.has_mx_record || !d.has_txt_record ? 0 : d.is_global && d.group !== 'admin' ? 3 @@ -180,19 +205,23 @@ async function listDomains(ctx) { } // store allDomains used for alias modal dropdown - const allDomains = [...domains].filter((domain) => { - const member = domain.members.find((m) => m.user.id === ctx.state.user.id); - // hide ubuntu-related domains - if ( - member && - domain.plan === 'team' && - domain.has_txt_record && - Object.keys(config.ubuntuTeamMapping).includes(domain.name) && - member.group !== 'admin' - ) - return false; - return true; - }); + if (!ctx.api) { + ctx.state.allDomains = [...domains].filter((domain) => { + const member = domain.members.find( + (m) => m.user.id === ctx.state.user.id + ); + // hide ubuntu-related domains + if ( + member && + domain.plan === 'team' && + domain.has_txt_record && + Object.keys(config.ubuntuTeamMapping).includes(domain.name) && + member.group !== 'admin' + ) + return false; + return true; + }); + } // domains are already pre-sorted A-Z by 'name' so only use sortFn if passed if (sortFn) domains = _.sortBy(domains, [sortFn]); @@ -201,33 +230,39 @@ async function listDomains(ctx) { domains = _.reverse(domains); // slice for page - domains = domains.slice( - ctx.paginate.skip, - ctx.query.limit + ctx.paginate.skip - ); + if (!ctx.api || hasPagination) + domains = domains.slice( + ctx.paginate.skip, + ctx.query.limit + ctx.paginate.skip + ); // get storage quota for each domain - domains = await Promise.all( - domains.map(async (d) => { - if (d.is_global || d.plan === 'free') return d; - try { - const [storageUsed, storageUsedByAliases, maxQuotaPerAlias] = - await Promise.all([ - Domains.getStorageUsed(d._id, ctx.locale), - Domains.getStorageUsed(d._id, ctx.locale, true), - Domains.getMaxQuota(d._id) - ]); - d.storage_used = storageUsed; - d.storage_used_by_aliases = storageUsedByAliases; - d.storage_quota = maxQuotaPerAlias; - } catch (err) { - ctx.logger.fatal(err); - } + domains = await pMap( + domains, + async (d) => populateDomainStorage(d, ctx.locale), + { + concurrency: config.concurrency + } + ); - return d; - }) + // + // set HTTP headers for pagination + // + // + setPaginationHeaders( + ctx, + pageCount, + !ctx.api || hasPagination ? ctx.query.page : 1, + domains.length, + itemCount ); + // if API then return so it can hit v1 domains controller + if (ctx.api) { + ctx.state.domains = domains; + return next(); + } + // // set breadcrumbs // @@ -241,7 +276,7 @@ async function listDomains(ctx) { if (ctx.accepts('html')) return ctx.render('my-account/domains', { - allDomains, + allDomains: ctx.state.allDomains, domains, pageCount, itemCount, @@ -249,7 +284,7 @@ async function listDomains(ctx) { }); const table = await ctx.render('my-account/domains/_table', { - allDomains, + allDomains: ctx.state.allDomains, domains, pageCount, itemCount, diff --git a/app/controllers/web/my-account/list-emails.js b/app/controllers/web/my-account/list-emails.js index 1411cb17d..c40253bb5 100644 --- a/app/controllers/web/my-account/list-emails.js +++ b/app/controllers/web/my-account/list-emails.js @@ -10,10 +10,11 @@ const isSANB = require('is-string-and-not-blank'); const paginate = require('koa-ctx-paginate'); const config = require('#config'); +const setPaginationHeaders = require('#helpers/set-pagination-headers'); const { Domains, Emails, Aliases } = require('#models'); // eslint-disable-next-line complexity -async function listEmails(ctx) { +async function listEmails(ctx, next) { // user must be domain admin or alias owner of the email const [domains, aliases, goodDomains, count] = await Promise.all([ Domains.distinct('_id', { @@ -212,8 +213,8 @@ async function listEmails(ctx) { } ]; - let $sort = { created_at: -1 }; - if (ctx.query.sort) { + let $sort = { created_at: ctx.api ? 1 : -1 }; + if (isSANB(ctx.query.sort)) { const order = ctx.query.sort.startsWith('-') ? -1 : 1; $sort = { [order === -1 ? ctx.query.sort.slice(1) : ctx.query.sort]: order @@ -235,11 +236,20 @@ async function listEmails(ctx) { status: 1, envelope: 1, messageId: 1, - headers: 1, date: 1, subject: 1, - accepted: 1, - rejectedErrors: 1 + // omit the following fields if API + // - message + // - headers + // - accepted + // - rejectedErrors + ...(ctx.api + ? {} + : { + headers: 1, + accepted: 1, + rejectedErrors: 1 + }) } }, { @@ -258,27 +268,12 @@ async function listEmails(ctx) { ctx.state.emails = emails; ctx.state.itemCount = results[0]?.count; } else { - if (ctx.api) { - // omit the following fields - // - message - // - headers - // - accepted - // - rejectedErrors - // eslint-disable-next-line unicorn/no-array-callback-reference - ctx.body = await Emails.find(query) - .select('-message -headers -accepted -rejectedErrors') - .sort('-created_at') - .lean() - .exec(); - return; - } - const [emails, itemCount] = await Promise.all([ // eslint-disable-next-line unicorn/no-array-callback-reference Emails.find(query) .limit(ctx.query.limit) .skip(ctx.paginate.skip) - .sort(ctx.query.sort || '-created_at') + .sort(isSANB(ctx.query.sort) ? ctx.query.sort : '-created_at') .lean() .exec(), Emails.countDocuments(query) @@ -295,6 +290,20 @@ async function listEmails(ctx) { ctx.query.page ); + // + // set HTTP headers for pagination + // + // + setPaginationHeaders( + ctx, + ctx.state.pageCount, + ctx.query.page, + ctx.state.emails.length, + ctx.state.itemCount + ); + + if (ctx.api) return next(); + if (ctx.accepts('html')) return ctx.render('my-account/emails'); const table = await ctx.render('my-account/emails/_table'); diff --git a/app/controllers/web/my-account/list-logs.js b/app/controllers/web/my-account/list-logs.js index daea39471..b2505213a 100644 --- a/app/controllers/web/my-account/list-logs.js +++ b/app/controllers/web/my-account/list-logs.js @@ -396,7 +396,13 @@ async function listLogs(ctx) { Logs.find(query) .limit(ctx.query.limit) .skip(ctx.paginate.skip) - .sort(ctx.query.sort || '-created_at') + .sort( + isSANB(ctx.query.sort) + ? ctx.query.sort + : ctx.api + ? 'created_at' + : '-created_at' + ) .lean() .maxTimeMS(SIXTY_SECONDS) .exec(), diff --git a/app/controllers/web/my-account/retrieve-aliases.js b/app/controllers/web/my-account/retrieve-aliases.js index b16a63adf..023b12f6d 100644 --- a/app/controllers/web/my-account/retrieve-aliases.js +++ b/app/controllers/web/my-account/retrieve-aliases.js @@ -4,12 +4,16 @@ */ const _ = require('lodash'); +const dayjs = require('dayjs-with-plugins'); const isSANB = require('is-string-and-not-blank'); const mongoose = require('mongoose'); const paginate = require('koa-ctx-paginate'); +const { boolean } = require('boolean'); const { isEmail } = require('validator'); const Aliases = require('#models/aliases'); +const sendPaginationCheck = require('#helpers/send-pagination-check'); +const setPaginationHeaders = require('#helpers/set-pagination-headers'); const config = require('#config'); @@ -132,24 +136,68 @@ async function retrieveAliases(ctx, next) { `/my-account/domains/${ctx.state.domain.name}/members/` ))) ) { - // TODO: major optimization issue here - // eslint-disable-next-line unicorn/no-array-callback-reference - ctx.state.domain.aliases = await Aliases.find(query) - .populate( - 'user', - `id email ${config.passport.fields.displayName} ${config.userFields.isBanned}` - ) - .populate('domain', 'id name') - .lean() - .exec(); + // + // starting November 1st we enforce API pagination on this endpoint + // (unless user opts in beforehand using ?pagination=true) + // + const hasPagination = dayjs().isBefore('11/1/2024', 'M/D/YYYY') + ? boolean(ctx.query.pagination) + : true; + + // + // NOTE: we send a one-time email admins that we now offer pagination + // and with notice that starting November 1st list domains/aliases + // endpoints will be paginated to 1000 results max per page by default + // + if (!hasPagination) await sendPaginationCheck(ctx); + + const [aliases, itemCount] = await Promise.all([ + hasPagination + ? // eslint-disable-next-line unicorn/no-array-callback-reference + Aliases.find(query) + .limit(ctx.query.limit) + .skip(ctx.paginate.skip) + .sort(isSANB(ctx.query.sort) ? ctx.query.sort : 'created_at') + .populate( + 'user', + `id email ${config.passport.fields.displayName} ${config.userFields.isBanned}` + ) + .populate('domain', 'id name') + .lean() + .exec() + : // eslint-disable-next-line unicorn/no-array-callback-reference + Aliases.find(query) + .populate( + 'user', + `id email ${config.passport.fields.displayName} ${config.userFields.isBanned}` + ) + .populate('domain', 'id name') + .sort(isSANB(ctx.query.sort) ? ctx.query.sort : 'created_at') + .lean() + .exec(), + Aliases.countDocuments(query) + ]); + + ctx.state.domain.aliases = aliases; + + // + // set HTTP headers for pagination + // + // + setPaginationHeaders( + ctx, + hasPagination ? Math.ceil(itemCount / ctx.query.limit) : 1, + hasPagination ? 1 : ctx.query.page, + aliases.length, + itemCount + ); } else { const [aliases, itemCount] = await Promise.all([ // eslint-disable-next-line unicorn/no-array-callback-reference Aliases.find(query) .limit(ctx.query.limit) - // TODO: ctx.paginate.skip -> paginate is undefined (need to check where ctx.paginate is used) .skip(ctx.paginate.skip) - .sort(ctx.query.sort || 'name') + .sort(isSANB(ctx.query.sort) ? ctx.query.sort : 'name') .populate( 'user', `id email ${config.passport.fields.displayName} ${config.userFields.isBanned}` @@ -167,6 +215,18 @@ async function retrieveAliases(ctx, next) { ctx.state.pageCount, ctx.query.page ); + + // + // set HTTP headers for pagination + // + // + setPaginationHeaders( + ctx, + ctx.state.pageCount, + ctx.query.page, + aliases.length, + itemCount + ); } let i = ctx.state.domain.aliases.length; diff --git a/app/controllers/web/my-account/retrieve-domain.js b/app/controllers/web/my-account/retrieve-domain.js index d56cf1bf6..4b7997951 100644 --- a/app/controllers/web/my-account/retrieve-domain.js +++ b/app/controllers/web/my-account/retrieve-domain.js @@ -4,6 +4,7 @@ */ const path = require('node:path'); +const punycode = require('node:punycode'); const Boom = require('@hapi/boom'); const Meta = require('koa-meta'); @@ -38,7 +39,7 @@ async function retrieveDomain(ctx, next) { : ctx.request.body.domain; ctx.state.domain = ctx.state.domains.find((domain) => - [domain.id, domain.name].includes(id) + [domain.id, domain.name, punycode.toASCII(domain.name)].includes(id) ); // check if domain exists, and if it doesn't then check diff --git a/app/controllers/web/my-account/retrieve-domains.js b/app/controllers/web/my-account/retrieve-domains.js index dc46f2190..902681ec5 100644 --- a/app/controllers/web/my-account/retrieve-domains.js +++ b/app/controllers/web/my-account/retrieve-domains.js @@ -65,6 +65,14 @@ async function retrieveDomains(ctx, next) { }); } + // + // TODO: we need to optimize this and enforce limit/skip for pagination + // (however a ton of routes right now rely on this being populated) + // (therefore it should be conditionally implemented only for when we list domains) + // (e.g. GET /v1/domains or /my-account/domains URL's) + // (e.g. someone with 5000+ domains would experience quite some slowness here) + // + // eslint-disable-next-line unicorn/no-array-callback-reference ctx.state.domains = await Domains.find(query) .populate( diff --git a/app/controllers/web/my-account/retrieve-invite.js b/app/controllers/web/my-account/retrieve-invite.js index 4555ac9c0..495cac760 100644 --- a/app/controllers/web/my-account/retrieve-invite.js +++ b/app/controllers/web/my-account/retrieve-invite.js @@ -3,6 +3,8 @@ * SPDX-License-Identifier: BUSL-1.1 */ +const punycode = require('node:punycode'); + const Boom = require('@hapi/boom'); const isSANB = require('is-string-and-not-blank'); @@ -33,7 +35,11 @@ async function retrieveInvite(ctx) { ); // if the user already is an admin or member of domain with same name - const match = ctx.state.domains.find((d) => d.name === domain.name); + const match = ctx.state.domains.find( + (d) => + d.name === domain.name || + punycode.toASCII(d.name) === punycode.toASCII(domain.name) + ); if (match) return ctx.throw( Boom.badRequest(ctx.translateError('DOMAIN_ALREADY_EXISTS')) diff --git a/app/controllers/web/my-account/update-alias.js b/app/controllers/web/my-account/update-alias.js index 408e39e59..74e38b143 100644 --- a/app/controllers/web/my-account/update-alias.js +++ b/app/controllers/web/my-account/update-alias.js @@ -6,8 +6,7 @@ const Boom = require('@hapi/boom'); const _ = require('lodash'); -const toObject = require('#helpers/to-object'); -const { Users, Domains, Aliases } = require('#models'); +const Aliases = require('#models/aliases'); async function updateAlias(ctx, next) { ctx.state.alias = await Aliases.findById(ctx.state.alias._id); @@ -29,14 +28,7 @@ async function updateAlias(ctx, next) { ) ctx.client.publish('pgp_reload', ctx.state.alias.id); - if (ctx.api) { - ctx.state.alias = toObject(Aliases, ctx.state.alias); - ctx.state.alias.user = toObject(Users, ctx.state.user); - ctx.state.alias.domain = toObject(Domains, ctx.state.domain); - ctx.state.alias.domain.members = ctx.state.domain.members; - ctx.state.alias.domain.invites = ctx.state.domain.invites; - return next(); - } + if (ctx.api) return next(); ctx.flash('custom', { title: ctx.request.t('Success'), diff --git a/app/controllers/web/my-account/validate-domain.js b/app/controllers/web/my-account/validate-domain.js index 5c276e648..620857d3d 100644 --- a/app/controllers/web/my-account/validate-domain.js +++ b/app/controllers/web/my-account/validate-domain.js @@ -3,6 +3,8 @@ * SPDX-License-Identifier: BUSL-1.1 */ +const punycode = require('node:punycode'); + const Boom = require('@hapi/boom'); const _ = require('lodash'); const isFQDN = require('is-fqdn'); @@ -25,7 +27,10 @@ async function validateDomain(ctx, next) { ctx.request.body.domain = ctx.request.body.domain.trim().toLowerCase(); const match = ctx.state.domains.find( - (domain) => domain.name === ctx.request.body.domain + (domain) => + domain.name === ctx.request.body.domain || + punycode.toASCII(domain.name) === + punycode.toASCII(ctx.request.body.domain) ); if (match) { diff --git a/app/models/domains.js b/app/models/domains.js index 80ab4a2e7..6b622a8b9 100644 --- a/app/models/domains.js +++ b/app/models/domains.js @@ -1124,7 +1124,6 @@ Domains.plugin(mongooseCommonPlugin, { 'verified_email_sent_at', 'smtp_last_checked_at', 'smtp_verified_at', - 'has_smtp', 'smtp_suspended_sent_at', 'is_smtp_suspended', 'last_checked_at', @@ -1142,7 +1141,8 @@ Domains.plugin(mongooseCommonPlugin, { 'has_return_path_record', 'has_dmarc_record', 'smtp_emails_blocked', - 'tokens' + 'tokens', + 'webhook_key' ], mongooseHidden: { virtuals: { @@ -2272,11 +2272,8 @@ async function getMaxQuota(_id, locale = i18n.config.defaultLocale) { Domains.statics.getMaxQuota = getMaxQuota; +// eslint-disable-next-line complexity async function getStorageUsed(_id, _locale, aliasesOnly = false) { - let storageUsed = 0; - - const locale = _locale || domain.locale || i18n.config.defaultLocale; - // // calculate storage used across entire domain and its admin users domains // (this is rudimentary storage system and has edge cases) @@ -2289,10 +2286,15 @@ async function getStorageUsed(_id, _locale, aliasesOnly = false) { if (!domain) { throw Boom.notFound( - i18n.translateError('DOMAIN_DOES_NOT_EXIST_ANYWHERE', locale) + i18n.translateError( + 'DOMAIN_DOES_NOT_EXIST_ANYWHERE', + _locale || i18n.config.defaultLocale + ) ); } + const locale = _locale || domain.locale || i18n.config.defaultLocale; + // Safeguard to not check storage used for global domains if (domain.is_global) { throw new TypeError('Global domains not supported for storage'); @@ -2359,6 +2361,8 @@ async function getStorageUsed(_id, _locale, aliasesOnly = false) { ); } + let storageUsed = 0; + if (domainIds.length > 0) { if (typeof conn?.models?.Aliases?.aggregate !== 'function') { throw new TypeError('Aliases model is not ready'); diff --git a/app/models/emails.js b/app/models/emails.js index 9fadc534f..62e43e5c0 100644 --- a/app/models/emails.js +++ b/app/models/emails.js @@ -11,7 +11,6 @@ const Axe = require('axe'); const Boom = require('@hapi/boom'); const SpamScanner = require('spamscanner'); const _ = require('lodash'); -const addressParser = require('nodemailer/lib/addressparser'); const bytes = require('bytes'); const dayjs = require('dayjs-with-plugins'); const getStream = require('get-stream'); @@ -26,16 +25,19 @@ const noReplyList = require('reserved-email-addresses-list/no-reply-list.json'); const nodemailer = require('nodemailer'); const pEvent = require('p-event'); const parseErr = require('parse-err'); +const splitLines = require('split-lines'); const { Headers, Splitter, Joiner } = require('mailsplit'); const { Iconv } = require('iconv'); const { boolean } = require('boolean'); const { convert } = require('html-to-text'); const { isEmail } = require('validator'); -const { simpleParser } = require('mailparser'); const Aliases = require('./aliases'); const Domains = require('./domains'); const Users = require('./users'); + +const MessageSplitter = require('#helpers/message-splitter'); +const SMTPError = require('#helpers/smtp-error'); const checkSRS = require('#helpers/check-srs'); const config = require('#config'); const emailHelper = require('#helpers/email'); @@ -46,6 +48,9 @@ const getHeaders = require('#helpers/get-headers'); const i18n = require('#helpers/i18n'); const isCodeBug = require('#helpers/is-code-bug'); const logger = require('#helpers/logger'); +const parseAddresses = require('#helpers/parse-addresses'); +const parseHostFromDomainOrAddress = require('#helpers/parse-host-from-domain-or-address'); +const parseUsername = require('#helpers/parse-username'); const IP_ADDRESS = ip.address(); const NO_REPLY_USERNAMES = new Set(noReplyList); @@ -55,6 +60,18 @@ const MAX_DAYS_IN_ADVANCE_TO_MS = ms(HUMAN_MAX_DAYS_IN_ADVANCE); const HUMAN_MAX_BYTES = '50MB'; const MAX_BYTES = bytes(HUMAN_MAX_BYTES); const BYTES_15MB = bytes('15MB'); +const ADDRESS_KEYS = new Set([ + 'from', + 'to', + 'cc', + 'bcc', + 'sender', + 'reply-to', + 'delivered-to', + 'return-path' +]); +const SENDER_KEYS = new Set(['from', 'sender', 'reply-to']); +const RCPT_TO_KEYS = new Set(['to', 'cc', 'bcc']); const transporter = nodemailer.createTransport({ streamTransport: true, @@ -250,7 +267,10 @@ Emails.plugin(mongooseCommonPlugin, { 'message', 'locked_by', 'locked_at', - 'priority' + 'priority', + 'blocked_hashes', + 'has_blocked_hashes', + 'rejectedErrors' ] }); @@ -260,6 +280,18 @@ Emails.index( { partialFilterExpression: { locked_at: { $exists: true } } } ); +// +// remove "<" and ">" from `messageId` if present +// (makes it easier and cleaner for search) +// +Emails.pre('validate', function (next) { + if (!isSANB(this.messageId)) return next(); + if (this.messageId.startsWith('<')) this.messageId = this.messageId.slice(1); + if (this.messageId.endsWith('>')) + this.messageId = this.messageId.slice(0, -1); + return next(); +}); + // // validate envelope // @@ -752,9 +784,16 @@ Emails.post('save', async function (email) { } }); -Emails.statics.getMessage = async function (obj) { - if (Buffer.isBuffer(obj)) return obj; - if (obj instanceof mongoose.mongo.Binary) return obj.buffer; +Emails.statics.getMessage = async function (obj, returnString = false) { + if (Buffer.isBuffer(obj)) { + if (returnString) return obj.toString(); + return obj; + } + + if (obj instanceof mongoose.mongo.Binary) { + if (returnString) return obj.buffer.toString(); + return obj.buffer; + } // obj = { // _id: new ObjectId("..."), @@ -791,6 +830,14 @@ Emails.statics.getMessage = async function (obj) { // TODO: move bucket to root const bucket = new mongoose.mongo.GridFSBucket(this.db); + if (returnString) { + const raw = await getStream(bucket.openDownloadStream(obj._id), { + maxBuffer: MAX_BYTES + }); + + return raw; + } + const raw = await getStream.buffer(bucket.openDownloadStream(obj._id), { maxBuffer: MAX_BYTES }); @@ -814,6 +861,7 @@ Emails.statics.queue = async function ( // when using readable streams as content if sending fails then // nodemailer does not abort opened and not finished stream // + const info = await transporter.sendMail(options.message); // ensure the message is not more than 50 MB @@ -821,106 +869,88 @@ Emails.statics.queue = async function ( if (messageBytes > MAX_BYTES) throw Boom.badRequest(`Email size of ${HUMAN_MAX_BYTES} exceeded.`); - const splitter = new Splitter(); - const joiner = new Joiner(); + const messageSplitter = new MessageSplitter({ + maxBytes: MAX_BYTES + }); - splitter.on('data', (data) => { - if (data.type !== 'node' || data.root !== true) return; + // TODO: this is doing double the work (2x processing of stream unnecessarily) + // we should check (and provide body/etc if already parsed from on-data-smtp + // + const body = await getStream.buffer( + intoStream(info.message).pipe(messageSplitter) + ); - // - // NOTE: there is no current way in mailsplit to not parse headers with libmime - // so this was a quick workaround we implemented (note `headers.parsed` is false) - // - const headerLines = Buffer.concat(data._headersLines, data._headerlen); - const headers = new Headers(headerLines, { Iconv }); - const lines = headers.getList(); - - const isEnvelopeToEmpty = info.envelope.to.length === 0; - - // convert address name values to ascii or mime encoded - // - // - for (const lineKey of [ - 'from', - 'to', - 'cc', - 'bcc', - 'sender', - 'reply-to', - 'delivered-to', - 'return-path' - ]) { - const header = lines.find((line) => line.key === lineKey); - if (!header) continue; - const { key, value } = libmime.decodeHeader(header.line); - - if (!isSANB(value)) { - data.headers.remove(key); - continue; - } + if (messageSplitter.sizeExceeded) + throw new SMTPError('Size exceeded', { responseCode: 552 }); - const addresses = addressParser(value); + if (!messageSplitter.headersParsed) + throw new SMTPError('Headers unable to be parsed'); - if (!_.isArray(addresses) || _.isEmpty(addresses)) { - data.headers.remove(key); - continue; - } + const { headers } = messageSplitter; - const values = []; - for (const obj of addresses) { - if (_.isObject(obj) && isSANB(obj.address)) { - if (isSANB(obj.name) && !/^[\w ']*$/.test(obj.name)) { - // ascii or mime encoding - obj.name = /^[\u0020-\u007E]*$/.test(obj.name) - ? '"' + obj.name.replace(/([\\"])/g, '\\$1') + '"' - : libmime.encodeWord(obj.name, 'Q', 52); - } + const isEnvelopeToEmpty = info.envelope.to.length === 0; - values.push({ - name: obj.name, - address: obj.address - }); - } - } + // + // ensure from header is equal to the alias sending from + // (avoids confusing "Invalid DKIM signature" error message) + // + let from; - if (values.length === 0) { - data.headers.remove(key); - } else { - data.headers.update( - header.line.split(': ')[0], - values - .map((v) => (v.name ? `${v.name} <${v.address}>` : v.address)) - .join(', ') - ); + const lines = splitLines(headers.headers.toString('binary').trim()); - // - // in case the email was `raw`, the envelope won't be parsed right away - // so we rely on the parsed headers from `mailparser` to re-create envelope - // - // - if (options?.message?.raw) { - // envelope from - if ( - info.envelope.from === false && - ['from', 'sender', 'reply-to'].includes(key) - ) - info.envelope.from = values[0].address; - // envelope to - else if (isEnvelopeToEmpty && ['to', 'cc', 'bcc'].includes(key)) - info.envelope.to.push(...values.map((v) => v.address)); + for (const line of lines) { + const value = Buffer.from(line, 'binary').toString(); + const index = value.indexOf(': '); + const key = value.slice(0, index); + const lowercaseKey = key.toLowerCase(); + if (!ADDRESS_KEYS.has(lowercaseKey)) continue; + + const addresses = parseAddresses(value.slice(index + 2)); + if (!_.isArray(addresses) || _.isEmpty(addresses)) continue; + + // there should only be one value in From header + if (lowercaseKey === 'from' && addresses.length === 1) { + // + // rewrite from header to be without "+" symbol + // so that users can send with "+" address filtering + // + const name = parseUsername(addresses[0].address); // converts to ASCII + const domain = parseHostFromDomainOrAddress(addresses[0].address); // converts to ASCII + from = `${name}@${domain}`; // ASCII formatted From address header + } + + // + // in case the email was `raw`, the envelope won't be parsed right away + // so we rely on the parsed headers from `mailparser` to re-create envelope + // + // + if (options?.message?.raw) { + // envelope from + if ( + (info.envelope.from === false || lowercaseKey === 'from') && + SENDER_KEYS.has(lowercaseKey) + ) + info.envelope.from = addresses[0].address; + // envelope to + else if (isEnvelopeToEmpty && RCPT_TO_KEYS.has(lowercaseKey)) { + for (const address of addresses) { + if (info.envelope.to.includes(address.address)) continue; + info.envelope.to.push(address.address); } } } - }); + } - const message = await getStream.buffer( - intoStream(info.message).pipe(splitter).pipe(joiner) - ); + // convert address name values to ascii or mime encoded + // + // + for (const key of []) { + const value = headers.getFirst(key); - // TODO: if it contains any list/auto headers then block - // (maybe best to put this in pre-save hook?) - // - header starts with "list-" + if (!isSANB(value)) continue; + } + // NOTE: not sure what the below comment is referencing (?) // TODO: if smtp side has non encoded then throw error // @@ -1051,92 +1081,77 @@ Emails.statics.queue = async function ( throw Boom.notFound(i18n.translateError('ALIAS_IS_NOT_ENABLED', locale)); } - // TODO: switch to use `spamscanner.scan` instead - const parsed = await simpleParser(message, { - Iconv, - skipImageLinks: true, - skipHtmlToText: false, - skipTextToHtml: false, - skipTextLinks: true - }); - - const date = - parsed.headers.get('date') && _.isDate(parsed.headers.get('date')) - ? parsed.headers.get('date') - : _.isDate(options.date) - ? options.date - : new Date(); - const messageId = parsed.headers.get('message-id') || info.messageId; - const subject = parsed.headers.get('subject'); - - // - // ensure from header is equal to the alias sending from - // (avoids confusing "Invalid DKIM signature" error message) - // - let from; - - const fromHeader = parsed.headers.get('from'); - if (_.isObject(fromHeader) && Array.isArray(fromHeader.value)) { - fromHeader.value = fromHeader.value.filter( - (addr) => - _.isObject(addr) && - isSANB(addr.address) && - isEmail(addr.address, { ignore_max_length: true }) - ); - if (fromHeader.value.length === 1) - from = fromHeader.value[0].address.toLowerCase(); + // parse the date for SMTP queuing + let date = new Date(headers.getFirst('date')); + if ( + !date || + date.toString() === 'Invalid Date' || + date < ONE_SECOND_AFTER_UNIX_EPOCH || + !_.isDate(date) + ) { + date = + _.isDate(options.date) && options.date >= ONE_SECOND_AFTER_UNIX_EPOCH + ? options.date + : new Date(); } - // - // rewrite from header to be without "+" symbol - // so that users can send with "+" address filtering - // - if (from && from.includes('+')) { - const [name, domain] = from.split('@'); - from = `${name.split('+')[0]}@${domain}`; + // decode headers (e.g. for search) + const decodedHeaders = await getHeaders(headers); + let subject; + let messageId; + for (const key of Object.keys(decodedHeaders)) { + if (key.toLowerCase() === 'subject') subject = decodedHeaders[key]; + if (key.toLowerCase() === 'message-id') messageId = decodedHeaders[key]; } + if (!messageId && info.messageId) messageId = info.messageId; + if (!from) throw Boom.forbidden( i18n.translateError( 'INVALID_FROM_HEADER', locale, - `${!options.catchall && alias ? alias.name : '*'}@${domain.name}`, + `${ + !options.catchall && alias ? punycode.toASCII(alias.name) : '*' + }@${punycode.toASCII(domain.name)}`, `${config.urls.web}/${locale}/my-account/domains/${domain.name}/advanced-settings#catch-all-passwords`, `${config.urls.web}/${locale}/my-account/domains/${domain.name}/advanced-settings#catch-all-passwords` ) ); // if we're a catch-all then validate from ends with @domain - if ((options.catchall || !alias) && !from.endsWith(`@${domain.name}`)) + if ( + (options.catchall || !alias) && + !from.endsWith(`@${punycode.toASCII(domain.name)}`) + ) throw Boom.forbidden( i18n.translateError( 'INVALID_CATCHALL_FROM_HEADER', locale, - `@${domain.name}` + `@${punycode.toASCII(domain.name)}` ) ); // otherwise it must be a specific match to the alias else if ( !options.catchall && alias && - from !== `${alias.name}@${domain.name}` + from !== `${punycode.toASCII(alias.name)}@${punycode.toASCII(domain.name)}` ) throw Boom.forbidden( i18n.translateError( 'INVALID_FROM_HEADER', locale, - `${alias.name}@${domain.name}`, + `${punycode.toASCII(alias.name)}@${punycode.toASCII(domain.name)}`, `${config.urls.web}/${locale}/my-account/domains/${domain.name}/advanced-settings#catch-all-passwords`, `${config.urls.web}/${locale}/my-account/domains/${domain.name}/advanced-settings#catch-all-passwords` ) ); + const message = Buffer.concat([headers.build(), body]); + // // sanitize message and attachments // - // `parsed.attachments` - // if ( isSANB(info?.envelope?.from) && isEmail(info.envelope.from, { ignore_max_length: true }) && @@ -1156,19 +1171,14 @@ Emails.statics.queue = async function ( ![config.supportEmail, config.abuseEmail].includes(to.toLowerCase()) ) ) { - const [phishing, executables, arbitrary, viruses] = await Promise.all([ - scanner.getPhishingResults(parsed), - scanner.getExecutableResults(parsed), - scanner.getArbitraryResults(parsed), - scanner.getVirusResults(parsed) - ]); + const scan = await scanner.scan(message); const messages = [ ...new Set([ - ...phishing.messages, - ...executables, - ...arbitrary, - ...viruses + ...scan.results.phishing, + ...scan.results.executables, + ...scan.results.arbitrary, + ...scan.results.viruses ]) ]; @@ -1227,17 +1237,11 @@ Emails.statics.queue = async function ( // needs to be forbidden so it gets mapped to 5xx error const error = Boom.forbidden(messages.join(' ')); - error.messages = messages; - error.phishing = phishing; - error.executables = executables; - error.arbitrary = arbitrary; - error.viruses = viruses; + error.scan = scan; throw error; } } - const headers = await getHeaders(parsed); - const status = _.isDate(domain.smtp_suspended_sent_at) || options?.isPending === true ? 'pending' @@ -1250,7 +1254,7 @@ Emails.statics.queue = async function ( envelope: info.envelope, message, messageId, - headers, + headers: decodedHeaders, date, subject, status, diff --git a/app/models/logs.js b/app/models/logs.js index ec58c1a18..9a6fbc13b 100644 --- a/app/models/logs.js +++ b/app/models/logs.js @@ -11,7 +11,6 @@ const { isIP } = require('node:net'); const Graceful = require('@ladjs/graceful'); const Redis = require('@ladjs/redis'); const _ = require('lodash'); -const addressParser = require('nodemailer/lib/addressparser'); const ansiHTML = require('ansi-html-community'); const bytes = require('bytes'); const captainHook = require('captain-hook'); @@ -48,6 +47,7 @@ const createTangerine = require('#helpers/create-tangerine'); const emailHelper = require('#helpers/email'); // const isErrorConstructorName = require('#helpers/is-error-constructor-name'); const logger = require('#helpers/logger'); +const parseAddresses = require('#helpers/parse-addresses'); const parseRootDomain = require('#helpers/parse-root-domain'); // headers that we store values for @@ -398,7 +398,7 @@ Logs.pre('save', function (next) { else keywords.add(meta.session.headers[key]); // - const addresses = addressParser(meta.session.headers[key]); + const addresses = parseAddresses(meta.session.headers[key]); if (Array.isArray(addresses) && addresses.length > 0) { for (const obj of addresses) { // if (isSANB(obj.name)) { diff --git a/app/models/users.js b/app/models/users.js index 81ae2ed38..13d5fe33a 100644 --- a/app/models/users.js +++ b/app/models/users.js @@ -80,7 +80,10 @@ const omitExtraFields = [ config.userFields.hasDenylistRequests, config.userFields.approvedDomains, config.userFields.isRemoved, - config.userFields.smtpLimit + config.userFields.smtpLimit, + + config.userFields.apiPastDueSentAt, + config.userFields.apiRestrictedSentAt ]; const Passkey = new mongoose.Schema({ diff --git a/app/views/_footer.pug b/app/views/_footer.pug index cfd57ce79..ad0741848 100644 --- a/app/views/_footer.pug +++ b/app/views/_footer.pug @@ -109,6 +109,9 @@ footer.mt-auto(aria-label=t("Footer")) li.list-inline-item= t("SEPA Direct Debit") li.list-inline-item= t("Canadian pre-authorized debits") li.list-inline-item= t("ACH Direct Debit") + li.list-inline-item= t("Bank Transfer") + li.list-inline-item= t("Domestic Wire Transfer (Enterprise)") + li.list-inline-item= t("International Wire Transfer (Enterprise)") .d-flex.flex-column.flex-lg-row if !isBot(ctx.get('User-Agent')) .flex-nowrap.order-3.order-lg-0.d-flex.flex-column.flex-grow-1.mr-lg-3 diff --git a/app/views/api/index.md b/app/views/api/index.md index 6b027c7c3..f0805df45 100644 --- a/app/views/api/index.md +++ b/app/views/api/index.md @@ -15,12 +15,37 @@ * [Create account](#create-account) * [Retrieve account](#retrieve-account) * [Update account](#update-account) -* [Emails](#emails) - * [Get email limit](#get-email-limit) - * [List emails](#list-emails) - * [Create email](#create-email) - * [Retrieve email](#retrieve-email) - * [Delete email](#delete-email) +* [Alias Contacts (CardDAV)](#alias-contacts-carddav) + * [List contacts](#list-contacts) + * [Create contact](#create-contact) + * [Retrieve contact](#retrieve-contact) + * [Update contact](#update-contact) + * [Delete contact](#delete-contact) +* [Alias Calendars (CalDAV)](#alias-calendars-caldav) + * [List calendars](#list-calendars) + * [Create calendar](#create-calendar) + * [Retrieve calendar](#retrieve-calendar) + * [Update calendar](#update-calendar) + * [Delete calendar](#delete-calendar) +* [Alias Messages (IMAP/POP3)](#alias-messages-imappop3) + * [List and search for messages](#list-and-search-for-messages) + * [Create message](#create-message) + * [Retrieve message](#retrieve-message) + * [Update message](#update-message) + * [Delete message](#delete-message) +* [Alias Folders (IMAP/POP3)](#alias-folders-imappop3) + * [List folders](#list-folders) + * [Create folder](#create-folder) + * [Retrieve folder](#retrieve-folder) + * [Update folder](#update-folder) + * [Delete folder](#delete-folder) + * [Copy folder](#copy-folder) +* [Outbound Emails](#outbound-emails) + * [Get outbound SMTP email limit](#get-outbound-smtp-email-limit) + * [List outbound SMTP emails](#list-outbound-smtp-emails) + * [Create outbound SMTP email](#create-outbound-smtp-email) + * [Retrieve outbound SMTP email](#retrieve-outbound-smtp-email) + * [Delete outbound SMTP email](#delete-outbound-smtp-email) * [Domains](#domains) * [List domains](#list-domains) * [Create domain](#create-domain) @@ -69,7 +94,9 @@ The current HTTP base URI path is: `BASE_URI`. ## Authentication -All endpoints require your [API key](https://forwardemail.net/my-account/security) to be set as the "username" value of the request's [Basic Authorization](https://en.wikipedia.org/wiki/Basic_access_authentication) header. Don't worry – examples are provided below for you if you're not sure what this is. +All endpoints require your [API key](https://forwardemail.net/my-account/security) to be set as the "username" value of the request's [Basic Authorization](https://en.wikipedia.org/wiki/Basic_access_authentication) header (with the exception of [Alias Contacts](#alias-contacts), [Alias Calendars](#alias-calendars), and [Alias Mailboxes](#alias-mailboxes) which use a [generated alias username and password](/faq#do-you-support-receiving-email-with-imap)).. + +Don't worry – examples are provided below for you if you're not sure what this is. ## Errors @@ -108,7 +135,35 @@ Our service is translated to over 25 different languages. All API response messa ## Pagination -If you would like to be notified when pagination is available, then please email . +> **NOTE:** As of November 1st, 2024 the API endpoints for [List domains](#list-domains) and [List domain aliases](#list-domain-aliases) will default to `1000` max results per page. If you would like to opt-in to this behavior early, you can pass `?paginate=true` as an additional querystring parameter to the URL for the endpoint query. + +Pagination is supported by all API endpoints that list results. + +Simply provide the querystring properties `page` (and optionally `limit`). + +The property `page` should be a number greater than or equal to `1`. If you provide `limit` (also a number), then the minimum value is `10` and maximum is `50` (unless otherwise noted). + +| Querystring Parameter | Required | Type | Description | +| --------------------- | -------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `page` | No | Number | Page of results to return. If not specified, the `page` value will be `1`. Must be a number greater than or equal to `1`. | +| `limit` | No | Number | Number of results to return per page. Defaults to `10` if not specified. Must be a number greater than or equal to `1`, and less than or equal to `50`. | + +In order to determine whether or not more results are available, we provide these HTTP response headers (which you can parse in order to paginate programmatically): + +| HTTP Response Header | Example | Description | +| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `X-Page-Count` | `X-Page-Count: 3` | The total page count available. | +| `X-Page-Current` | `X-Page-Current: 1` | The current page of results returned (e.g. based off `page` querystring parameter). | +| `X-Page-Size` | `X-Page-Size: 10` | The total number of results in the page returned (e.g. based off `limit` querystring parameter and actual results returned). | +| `X-Item-Count` | `X-Item-Count: 30` | The total number of items available across all pages. | +| `Link` | `Link: ; rel="prev", ; rel="next", Example Request: + +```sh +curl BASE_URI/v1/domains/DOMAIN_NAME/aliases?page=2 \ + -u API_TOKEN: +``` ## Logs @@ -208,11 +263,183 @@ curl -X PUT BASE_URI/v1/account \ ``` -## Emails +## Alias Contacts (CardDAV) + +> **NOTE:** Unlike other API endpoints, these require [Authentication](#authentication) "username" equal to the alias username and "password" equal to the alias generated password as Basic Authorization headers. + +> **WIP:** This endpoint section is a work in progress and will be released (hopefully) in 2024. In the interim please use an IMAP client from the "Apps" dropdown in the navigation of our website. + +> **NOTE:** [CardDAV support is not yet available, follow this discussion on GitHub for updates](https://github.com/orgs/forwardemail/discussions/274). + +### List contacts + +> `GET /v1/contacts` + +**Coming soon** + +### Create contact + +> `POST /v1/contacts` + +**Coming soon** + +### Retrieve contact + +> `GET /v1/contacts/:id` + +**Coming soon** + +### Update contact + +> `PUT /v1/contacts/:id` + +**Coming soon** + +### Delete contact + +> `DELETE /v1/contacts/:id` + +**Coming soon** + + +## Alias Calendars (CalDAV) + +> **NOTE:** Unlike other API endpoints, these require [Authentication](#authentication) "username" equal to the alias username and "password" equal to the alias generated password as Basic Authorization headers. + +> **WIP:** This endpoint section is a work in progress and will be released (hopefully) in 2024. In the interim please use an IMAP client from the "Apps" dropdown in the navigation of our website. + +### List calendars + +> `GET /v1/calendars` + +**Coming soon** + +### Create calendar + +> `POST /v1/calendars` + +**Coming soon** + +### Retrieve calendar + +> `GET /v1/calendars/:id` + +**Coming soon** + +### Update calendar + +> `PUT /v1/calendars/:id` + +**Coming soon** + +### Delete calendar + +> `DELETE /v1/calendars/:id` + +**Coming soon** + + +## Alias Messages (IMAP/POP3) + +> **NOTE:** Unlike other API endpoints, these require [Authentication](#authentication) "username" equal to the alias username and "password" equal to the alias generated password as Basic Authorization headers. + +> **WIP:** This endpoint section is a work in progress and will be released (hopefully) in 2024. In the interim please use an IMAP client from the "Apps" dropdown in the navigation of our website. -Please ensure that you have followed setup instructions for your domain. These instructions can be found at [My Account → Domains → Settings → Outbound SMTP Configuration](/my-account/domains). You need to ensure setup of DKIM, Return-Path, and DMARC for sending outbound SMTP with your domain. +Please ensure that you have followed setup instructions for your domain. -### Get email limit +These instructions can be found in our FAQ section [Do you support receiving email with IMAP?](/faq#do-you-support-receiving-email-with-imap). + +### List and search for messages + +> `GET /v1/messages` + +**Coming soon** + +### Create message + +> **NOTE:** This will **NOT** send an email – it will only simply add the message to your mailbox folder (e.g. this is similar to the IMAP `APPEND` command). If you would like to send an email, then see [Create outbound SMTP email](#create-outbound-smtp-email) below. After creating the outbound SMTP email, then you can append a copy of it using this endpoint to your alias' mailbox for storage purposes. + +> `POST /v1/messages` + +**Coming soon** + +### Retrieve message + +> `GET /v1/messages/:id` + +**Coming soon** + +### Update message + +> `PUT /v1/messages/:id` + +**Coming soon** + +### Delete message + +> `DELETE /v1/messages:id` + +**Coming soon** + + +## Alias Folders (IMAP/POP3) + +
+ + + Tip: + + + Folder endpoints with a folder's path /v1/folders/:path as their endpoint are interchangeable with a folder's ID :id. This means you can refer to the folder by either its path or id value. + +
+ +> **WIP:** This endpoint section is a work in progress and will be released (hopefully) in 2024. In the interim please use an IMAP client from the "Apps" dropdown in the navigation of our website. + +### List folders + +> `GET /v1/folders` + +**Coming soon** + +### Create folder + +> `POST /v1/folders` + +**Coming soon** + +### Retrieve folder + +> `GET /v1/folders/:id` + +**Coming soon** + +### Update folder + +> `PUT /v1/folders/:id` + +**Coming soon** + +### Delete folder + +> `DELETE /v1/folders/:id` + +**Coming soon** + +### Copy folder + +> `POST /v1/folders/:id/copy` + +**Coming soon** + + +## Outbound Emails + +Please ensure that you have followed setup instructions for your domain. + +These instructions can be found at [My Account → Domains → Settings → Outbound SMTP Configuration](/my-account/domains). You need to ensure setup of DKIM, Return-Path, and DMARC for sending outbound SMTP with your domain. + +### Get outbound SMTP email limit This is a simple endpoint that returns a JSON object containing the `count` and `limit` for the number of daily SMTP outbound messages on a per account basis. @@ -225,22 +452,21 @@ curl BASE_URI/v1/emails/limit \ -u API_TOKEN: ``` -### List emails +### List outbound SMTP emails -Note that this endpoint does not return an already created email's `message`, `headers`, `accepted`, nor `rejectedErrors` properties. +Note that this endpoint does not return property values for an email's `message`, `headers`, nor `rejectedErrors`. To return those properties and their values, please use the [Retrieve email](#retrieve-email) endpoint with an email ID. -This endpoint will return at most `50` results at a time. If you want to query for multiple pages, then append `?page=NUMBER` where `NUMBER` is an integer, e.g. `?page=1`. - > `GET /v1/emails` -| Querystring Parameter | Required | Type | Description | -| --------------------- | -------- | ------------------------- | -------------------------------------------------------------------------------------------- | -| `q` | No | String (RegExp supported) | Search for emails by metadata | -| `domain` | No | String (RegExp supported) | Search for emails by domain name | -| `page` | No | Number | Page to return of results (default is `1`) | -| `limit | No | Number | Number of results per page to return (default is `50` – the max is `50` and minimum is `10`) | +| Querystring Parameter | Required | Type | Description | +| --------------------- | -------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | +| `q` | No | String (RegExp supported) | Search for emails by metadata | +| `domain` | No | String (RegExp supported) | Search for emails by domain name | +| `sort` | No | String | Sort by a specific field (prefix with a single hyphen `-` to sort in the reverse direction of that field). Defaults to `created_at` if not set. | +| `page` | No | Number | See [Pagination](#pagination) for more insight | +| `limit` | No | Number | See [Pagination](#pagination) for more insight | > Example Request: @@ -249,7 +475,7 @@ curl BASE_URI/v1/emails \ -u API_TOKEN: ``` -### Create email +### Create outbound SMTP email Our API for creating an email is inspired by and leverages Nodemailer's message option configuration. Please defer to the [Nodemailer message configuration](https://nodemailer.com/message/) for all body parameters below. @@ -306,7 +532,7 @@ curl -X POST BASE_URI/v1/emails \ -d "raw=`cat file.eml`" ``` -### Retrieve email +### Retrieve outbound SMTP email > `GET /v1/emails/:id` @@ -317,7 +543,7 @@ curl BASE_URI/v1/emails/:id \ -u API_TOKEN: ``` -### Delete email +### Delete outbound SMTP email Email deletion will set the status to `"rejected"` (and subsequently not process it in the queue) if and only if the current status is one of `"pending"`, `"queued"`, or `"deferred"`. We may purge emails automatically after 30 days after they were created and/or sent – therefore you should keep a copy of outbound SMTP emails in your client, database, or application. You can reference our email ID value in your database if desired – this value is returned from both [Create email](#create-email) and [Retrieve email](#retrieve-email) endpoints. @@ -339,18 +565,23 @@ curl -X DELETE BASE_URI/v1/emails/:id \ Tip: - Domain endpoints with a domain's name /v1/domains/:domain_name as their path are interchangeable with a domain's ID :domain_id. This means you can refer to the domain by either its name or id value. + Domain endpoints with a domain's name /v1/domains/:domain_name as their endpoint are interchangeable with a domain's ID :domain_id. This means you can refer to the domain by either its name or id value. ### List domains +> **NOTE:** As of November 1st, 2024 the API endpoints for [List domains](#list-domains) and [List domain aliases](#list-domain-aliases) will default to `1000` max results per page. If you would like to opt-in to this behavior early, you can pass `?paginate=true` as an additional querystring parameter to the URL for the endpoint query. See [Pagination](#pagination) for more insight. + > `GET /v1/domains` -| Querystring Parameter | Required | Type | Description | -| --------------------- | -------- | ------------------------- | -------------------------- | -| `q` | No | String (RegExp supported) | Search for domains by name | -| `name` | No | String (RegExp supported) | Search for domains by name | +| Querystring Parameter | Required | Type | Description | +| --------------------- | -------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | +| `q` | No | String (RegExp supported) | Search for domains by name | +| `name` | No | String (RegExp supported) | Search for domains by name | +| `sort` | No | String | Sort by a specific field (prefix with a single hyphen `-` to sort in the reverse direction of that field). Defaults to `created_at` if not set. | +| `page` | No | Number | See [Pagination](#pagination) for more insight | +| `limit` | No | Number | See [Pagination](#pagination) for more insight | > Example Request: @@ -543,13 +774,18 @@ curl -X POST BASE_URI/v1/domains/DOMAIN_NAME/aliases/ALIAS_ID/generate-password ### List domain aliases +> **NOTE:** As of November 1st, 2024 the API endpoints for [List domains](#list-domains) and [List domain aliases](#list-domain-aliases) will default to `1000` max results per page. If you would like to opt-in to this behavior early, you can pass `?paginate=true` as an additional querystring parameter to the URL for the endpoint query. See [Pagination](#pagination) for more insight. + > `GET /v1/domains/DOMAIN_NAME/aliases` -| Querystring Parameter | Required | Type | Description | -| --------------------- | -------- | ------------------------- | ----------------------------------------------------------- | -| `q` | No | String (RegExp supported) | Search for aliases in a domain by name, label, or recipient | -| `name` | No | String (RegExp supported) | Search for aliases in a domain by name | -| `recipient` | No | String (RegExp supported) | Search for aliases in a domain by recipient | +| Querystring Parameter | Required | Type | Description | +| --------------------- | -------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | +| `q` | No | String (RegExp supported) | Search for aliases in a domain by name, label, or recipient | +| `name` | No | String (RegExp supported) | Search for aliases in a domain by name | +| `recipient` | No | String (RegExp supported) | Search for aliases in a domain by recipient | +| `sort` | No | String | Sort by a specific field (prefix with a single hyphen `-` to sort in the reverse direction of that field). Defaults to `created_at` if not set. | +| `page` | No | Number | See [Pagination](#pagination) for more insight | +| `limit` | No | Number | See [Pagination](#pagination) for more insight | > Example Request: diff --git a/app/views/faq/index.md b/app/views/faq/index.md index 1c551319a..13f7ffbde 100644 --- a/app/views/faq/index.md +++ b/app/views/faq/index.md @@ -875,7 +875,7 @@ Yes, as of May 2023 we support sending email with SMTP as an add-on for all paid Important: - If you are using Gmail, then refer to our Send Mail As with Gmail guide. If you are a developer, then refer to our email API docs. + If you are using Gmail, then refer to our Send Mail As with Gmail guide. If you are a developer, then refer to our email API docs. @@ -1014,7 +1014,7 @@ Yes, as of May 2023 we support sending email with API as an add-on for all paid -Please view our section on [Emails](/email-api#emails) in our API documentation for options, examples, and more insight. +Please view our section on [Emails](/email-api#outbound-emails) in our API documentation for options, examples, and more insight. In order to send outbound email with our API, you must use your API token available under [My Security](/my-account/security). @@ -1305,7 +1305,7 @@ You can change a calendar's name and color after creation – just use your pref Important: - If you are a developer, then refer to our email API docs. + If you are a developer, then refer to our email API docs. diff --git a/app/views/my-account/domains/advanced-settings.pug b/app/views/my-account/domains/advanced-settings.pug index 45a0c8cb8..3bf7b329a 100644 --- a/app/views/my-account/domains/advanced-settings.pug +++ b/app/views/my-account/domains/advanced-settings.pug @@ -338,7 +338,7 @@ block body target="_blank" )= t("Send via SMTP") li.list-inline-item.mb-3.mb-md-0: a.btn.btn-sm.btn-dark( - href=l("/email-api#emails"), + href=l("/email-api#outbound-emails"), target="_blank" )= t("Send via API") li.list-inline-item diff --git a/app/views/my-account/domains/billing.pug b/app/views/my-account/domains/billing.pug index a07008f5d..2a26a1e02 100644 --- a/app/views/my-account/domains/billing.pug +++ b/app/views/my-account/domains/billing.pug @@ -141,7 +141,7 @@ block body data-confirm-type="info", data-confirm-show-cancel-button="false", data-confirm-prompt-title=t("Payment Methods"), - data-confirm-prompt-html=t("We accept Visa, Mastercard, American Express, Discover, Diners Club, JCB, China UnionPay, Alipay, Apple Pay, Google Pay, Amazon Pay, Cash App, Link, Bancontact, EPS, giropay, iDEAL, Przelewy24, Sofort, Affirm, Afterpay / Clearpay, Klarna, SEPA Direct Debit, Canadian pre-authorized debits, and ACH Direct Debit.") + data-confirm-prompt-html=t("We accept Visa, Mastercard, American Express, Discover, Diners Club, JCB, China UnionPay, Alipay, Apple Pay, Google Pay, Amazon Pay, Cash App, Link, Bancontact, EPS, giropay, iDEAL, Przelewy24, Sofort, Affirm, Afterpay / Clearpay, Klarna, SEPA Direct Debit, Canadian pre-authorized debits, ACH Direct Debit, and Bank Transfer.") ) i.fa.fa-info-circle .form-check.form-check-inline.mr-0.no-js diff --git a/app/views/my-account/domains/verify-smtp.pug b/app/views/my-account/domains/verify-smtp.pug index 6936f5fbc..1fced2a23 100644 --- a/app/views/my-account/domains/verify-smtp.pug +++ b/app/views/my-account/domains/verify-smtp.pug @@ -85,7 +85,7 @@ block body target="_blank" )= t("Send via SMTP") li.list-inline-item.d-block.d-md-inline-block: a.btn.btn-lg.btn-dark.btn-block( - href=l("/email-api#emails"), + href=l("/email-api#outbound-emails"), target="_blank" )= t("Send via API") .container.text-center.mb-3 diff --git a/config/phrases.js b/config/phrases.js index 150e1d9d7..f8086fbb9 100644 --- a/config/phrases.js +++ b/config/phrases.js @@ -20,6 +20,10 @@ for (const key of Object.keys(statuses.message)) { } module.exports = { + PAGINATION_CHECK_SUBJECT: + 'Notice: API pagination required starting November 1st', + PAGINATION_CHECK_MESSAGE: + 'Starting November 1st of this year we will be enforcing API pagination on our API endpoints for list domains and list domain aliases. Learn more about our approach to API pagination and how you can opt-in beforehand at %s.', RESTRICTED_ALIAS_DETECTED_SUBJECT: '%s has restricted alias name(s) detected', RESTRICTED_ALIAS_DETECTED_MESSAGE: diff --git a/helpers/create-websocket-as-promised.js b/helpers/create-websocket-as-promised.js index 7cec2360c..6a362aba4 100644 --- a/helpers/create-websocket-as-promised.js +++ b/helpers/create-websocket-as-promised.js @@ -206,6 +206,45 @@ function createWebSocketClass(options) { }; } +async function sendRequest(wsp, requestId, data) { + data.sent_at = Date.now(); + + if (!wsp.isOpened) { + await pWaitFor( + async () => { + try { + await wsp.open(); + return true; + } catch (err) { + err.wsData = data; + logger.fatal(err); + return false; + } + }, + { + timeout: config.env === 'test' ? ms('3s') : ms('15s') + } + ); + } + + return wsp.sendRequest(data, { + timeout: + typeof data.timeout === 'number' && + Number.isFinite(data.timeout) && + data.timeout > 0 + ? data.timeout + : config.env === 'production' + ? // + // TODO: we should revise this later in future + // (no wsp.request methds should take longer than 1m) + // (any long-running jobs should have emails sent once completed) + // + ms('10m') // <--- TODO: we should not have 10m in future (should be 30-60s max) + : ms('10s'), + requestId + }); +} + function createWebSocketAsPromised(options = {}) { // // @@ -293,9 +332,9 @@ function createWebSocketAsPromised(options = {}) { // 'onClose', 'onError' ]) { - wsp[event].addListener((...args) => - logger[event === 'onError' ? 'error' : 'debug'](event, { args }) - ); + wsp[event].addListener((...args) => { + logger[event === 'onError' ? 'error' : 'debug'](event, { args }); + }); } // @@ -327,56 +366,26 @@ function createWebSocketAsPromised(options = {}) { // attempt to send the request 3x // (e.g. in case connection disconnected and no response was made) - const response = await pRetry( - async () => { - data.sent_at = Date.now(); - - if (!wsp.isOpened) { - await pWaitFor( - async () => { - try { - await wsp.open(); - return true; - } catch (err) { - err.wsData = data; - logger.fatal(err); - return false; + const response = + retries === 0 + ? await sendRequest(wsp, requestId, data) + : await pRetry(() => sendRequest(wsp, requestId, data), { + retries, + minTimeout: config.busyTimeout / 2, + maxTimeout: config.busyTimeout, + factor: 1, + onFailedAttempt(error) { + error.isCodeBug = true; + error.wsData = data; + logger.error(error); + + if (isRetryableError(error)) { + return; } - }, - { - timeout: ms('15s') + + throw error; } - ); - } - - return wsp.sendRequest(data, { - timeout: - typeof data.timeout === 'number' && - Number.isFinite(data.timeout) && - data.timeout > 0 - ? data.timeout - : ms('10m'), - requestId - }); - }, - { - retries, - minTimeout: config.busyTimeout / 2, - maxTimeout: config.busyTimeout, - factor: 1, - onFailedAttempt(error) { - error.isCodeBug = true; - error.wsData = data; - logger.error(error); - - if (isRetryableError(error)) { - return; - } - - throw error; - } - } - ); + }); if ( !response.id || diff --git a/helpers/get-attributes.js b/helpers/get-attributes.js index d53d43a14..9821a95f4 100644 --- a/helpers/get-attributes.js +++ b/helpers/get-attributes.js @@ -4,33 +4,15 @@ */ const _ = require('lodash'); -const addrs = require('email-addresses'); -const addressParser = require('nodemailer/lib/addressparser'); const isSANB = require('is-string-and-not-blank'); -const { isEmail } = require('validator'); const checkSRS = require('#helpers/check-srs'); const parseHostFromDomainOrAddress = require('#helpers/parse-host-from-domain-or-address'); const parseRootDomain = require('#helpers/parse-root-domain'); +const parseAddresses = require('#helpers/parse-addresses'); function getAttributes(headers, session) { - const replyTo = headers.getFirst('reply-to'); - - let replyToAddresses = - addrs.parseAddressList({ input: replyTo, partial: true }) || []; - - if (replyToAddresses.length === 0) - replyToAddresses = addrs.parseAddressList({ input: replyTo }) || []; - - // safeguard - if (replyToAddresses.length === 0) replyToAddresses = addressParser(replyTo); - - replyToAddresses = replyToAddresses.filter( - (addr) => - _.isObject(addr) && - isSANB(addr.address) && - isEmail(addr.address, { ignore_max_length: true }) - ); + const replyToAddresses = parseAddresses(headers.getFirst('reply-to')); // // check if the From, Reply-To, MAIL FROM, sender IP/host, or RCPT TO were silent banned diff --git a/helpers/get-forwarding-addresses.js b/helpers/get-forwarding-addresses.js index dfa8ed7c6..2bcd9cbfa 100644 --- a/helpers/get-forwarding-addresses.js +++ b/helpers/get-forwarding-addresses.js @@ -8,7 +8,6 @@ const { Buffer } = require('node:buffer'); const RE2 = require('re2'); const _ = require('lodash'); -const addressParser = require('nodemailer/lib/addressparser'); const isBase64 = require('is-base64'); const isFQDN = require('is-fqdn'); const isSANB = require('is-string-and-not-blank'); @@ -22,6 +21,7 @@ const config = require('#config'); const env = require('#config/env'); const getErrorCode = require('#helpers/get-error-code'); const logger = require('#helpers/logger'); +const parseAddresses = require('#helpers/parse-addresses'); const parseHostFromDomainOrAddress = require('#helpers/parse-host-from-domain-or-address'); const parseRootDomain = require('#helpers/parse-root-domain'); const parseUsername = require('#helpers/parse-username'); @@ -30,7 +30,7 @@ const { decrypt } = require('#helpers/encrypt-decrypt'); const USER_AGENT = `${config.pkg.name}/${config.pkg.version}`; function parseFilter(address) { - ({ address } = addressParser(address)[0]); + ({ address } = parseAddresses(address)[0]); return address.includes('+') ? address.split('+')[1].split('@')[0] : ''; } diff --git a/helpers/get-from-address.js b/helpers/get-from-address.js index 7f30f88b8..6e63ab7a1 100644 --- a/helpers/get-from-address.js +++ b/helpers/get-from-address.js @@ -3,14 +3,11 @@ * SPDX-License-Identifier: BUSL-1.1 */ -const _ = require('lodash'); -const addressParser = require('nodemailer/lib/addressparser'); -const addrs = require('email-addresses'); -const isSANB = require('is-string-and-not-blank'); -const { isEmail } = require('validator'); +const punycode = require('node:punycode'); const SMTPError = require('#helpers/smtp-error'); const checkSRS = require('#helpers/check-srs'); +const parseAddresses = require('#helpers/parse-addresses'); function getFromAddress(originalFrom) { if (!originalFrom) @@ -26,36 +23,17 @@ function getFromAddress(originalFrom) { // // TODO: we probably should rewrite this with something else (!!!!) // - let originalFromAddresses = - addrs.parseAddressList({ input: originalFrom, partial: true }) || []; + const originalFromAddresses = parseAddresses(originalFrom); - if (originalFromAddresses.length === 0) - originalFromAddresses = - addrs.parseAddressList({ input: originalFrom }) || []; - - // safeguard - if (originalFromAddresses.length === 0) - originalFromAddresses = addressParser(originalFrom); - - const originalLength = originalFromAddresses.length; - - originalFromAddresses = originalFromAddresses.filter( - (addr) => - _.isObject(addr) && - isSANB(addr.address) && - isEmail(addr.address, { ignore_max_length: true }) - ); - - if ( - originalFromAddresses.length !== 1 || - originalLength !== originalFromAddresses.length - ) + if (originalFromAddresses.length !== 1) throw new SMTPError( 'Your message must contain one valid email address in the "From" header' ); // set original from address that was parsed - return checkSRS(originalFromAddresses[0].address).toLowerCase(); + return checkSRS( + punycode.toASCII(originalFromAddresses[0].address) + ).toLowerCase(); } module.exports = getFromAddress; diff --git a/helpers/get-headers.js b/helpers/get-headers.js index eeb4c38a5..f132eb795 100644 --- a/helpers/get-headers.js +++ b/helpers/get-headers.js @@ -3,15 +3,42 @@ * SPDX-License-Identifier: BUSL-1.1 */ +const { Buffer } = require('node:buffer'); + +const splitLines = require('split-lines'); + function getHeaders(headers) { const _headers = {}; - const lines = headers.headers - .toString('binary') - .replace(/[\r\n]+$/, '') - .split(/\r?\n/); + const lines = splitLines(headers.headers.toString('binary').trim()); + + // + // NOTE: we decode header values because + // want them to be easily searchable + // (e.g. an emoji in a header line gets encoded as: + // > '=?UTF-8?Q?=F0=9F=8E=89_beep?=' + // and we want output that looks like + // > 🎉 beep + // (e.g. so a user could search for 🎉) + // for (const line of lines) { - const index = line.indexOf(': '); - _headers[line.slice(0, index)] = line.slice(index + 2); + const value = Buffer.from(line, 'binary').toString(); + const index = value.indexOf(': '); + const key = value.slice(0, index); + + _headers[key] = value.slice(index + 2); + + // + if ( + ['subject', 'references', 'message-id', 'in-reply-to'].includes( + key.toLowerCase() + ) + ) { + try { + _headers[key] = headers.libmime.decodeWords(_headers[key]); + } catch { + // ignore, keep as is + } + } } return _headers; diff --git a/helpers/index.js b/helpers/index.js index 4cc29ee18..9dc234406 100644 --- a/helpers/index.js +++ b/helpers/index.js @@ -124,6 +124,10 @@ const getRecipients = require('./get-recipients'); const isAuthenticatedMessage = require('./is-authenticated-message'); const getForwardingAddresses = require('./get-forwarding-addresses'); const MessageSplitter = require('./message-splitter'); +const setPaginationHeaders = require('./set-pagination-headers'); +const sendPaginationCheck = require('./send-pagination-check'); +const populateDomainStorage = require('./populate-domain-storage'); +const parseAddresses = require('./parse-addresses'); module.exports = { decrypt, @@ -248,5 +252,9 @@ module.exports = { getRecipients, isAuthenticatedMessage, getForwardingAddresses, - MessageSplitter + MessageSplitter, + setPaginationHeaders, + sendPaginationCheck, + populateDomainStorage, + parseAddresses }; diff --git a/helpers/on-data-smtp.js b/helpers/on-data-smtp.js index 866e3750d..e3475ab42 100644 --- a/helpers/on-data-smtp.js +++ b/helpers/on-data-smtp.js @@ -62,7 +62,7 @@ async function sendRateLimitEmail(user) { } // eslint-disable-next-line complexity -async function onDataSMTP(raw, session) { +async function onDataSMTP(raw, session, date) { // // NOTE: we don't share the full alias and domain object // in between onAuth and onData because there could @@ -395,7 +395,7 @@ async function onDataSMTP(raw, session) { alias, domain, user, - date: new Date(session.arrivalDate), + date, catchall: typeof session?.user?.alias_id !== 'string', isPending: true }); diff --git a/helpers/on-data.js b/helpers/on-data.js index b5f8bd7bc..bf54d5971 100644 --- a/helpers/on-data.js +++ b/helpers/on-data.js @@ -6,14 +6,10 @@ const { Buffer } = require('node:buffer'); const _ = require('lodash'); -const addressParser = require('nodemailer/lib/addressparser'); -const addrs = require('email-addresses'); const bytes = require('bytes'); const getStream = require('get-stream'); -const isSANB = require('is-string-and-not-blank'); const pFilter = require('p-filter'); const safeStringify = require('fast-safe-stringify'); -const { isEmail } = require('validator'); const MessageSplitter = require('#helpers/message-splitter'); const SMTPError = require('#helpers/smtp-error'); @@ -24,16 +20,17 @@ const env = require('#config/env'); const isSilentBanned = require('#helpers/is-silent-banned'); const onDataMX = require('#helpers/on-data-mx'); const onDataSMTP = require('#helpers/on-data-smtp'); +const parseAddresses = require('#helpers/parse-addresses'); const parseHostFromDomainOrAddress = require('#helpers/parse-host-from-domain-or-address'); const parseRootDomain = require('#helpers/parse-root-domain'); const refineAndLogError = require('#helpers/refine-and-log-error'); const updateSession = require('#helpers/update-session'); +const ONE_SECOND_AFTER_UNIX_EPOCH = new Date(1000); const MAX_BYTES = bytes(env.SMTP_MESSAGE_MAX_SIZE); // TODO: check for `this.isClosing` before heavy/slow operations in onDataMX -// eslint-disable-next-line complexity async function onData(stream, _session, fn) { if (this.isClosing) return setImmediate(() => fn(new ServerShutdownError())); @@ -56,6 +53,7 @@ async function onData(stream, _session, fn) { throw new SMTPError('Headers unable to be parsed'); const { headers } = messageSplitter; + const raw = Buffer.concat([headers.build(), body]); // update session object with useful debug info for error logs @@ -152,38 +150,34 @@ async function onData(stream, _session, fn) { // in addition to RCPT TO being incorrect due to improperly configured server sending to SRS forwarded address // we also need to rewrite the "To" header an rewrite any SRS forwarded addresses with their actual ones // - let to = headers.getFirst('to'); - if (isSANB(to)) { - let originalToAddresses = - addrs.parseAddressList({ input: to, partial: true }) || []; - if (originalToAddresses.length === 0) - originalToAddresses = addrs.parseAddressList({ input: to }) || []; - // safeguard - if (originalToAddresses.length === 0) - originalToAddresses = addressParser(to); - originalToAddresses = originalToAddresses.filter( - (addr) => - _.isObject(addr) && - isSANB(addr.address) && - isEmail(addr.address, { ignore_max_length: true }) - ); - for (const obj of originalToAddresses) { - const shouldThrow = - parseRootDomain(parseHostFromDomainOrAddress(obj.address)) === - env.WEB_HOST; - // rewrite the to line - let isModified = false; - if (checkSRS(obj.address, shouldThrow) !== obj.address) { - isModified = true; - to = to.replaceAll(obj.address, checkSRS(obj.address, shouldThrow)); - } - - if (isModified) headers.update('to', to); - } + const originalToAddresses = parseAddresses(headers.getFirst('to')); + for (const obj of originalToAddresses) { + const shouldThrow = + parseRootDomain(parseHostFromDomainOrAddress(obj.address)) === + env.WEB_HOST; + // rewrite the to line + if (checkSRS(obj.address, shouldThrow) !== obj.address) + headers.update( + 'to', + headers + .getFirst('to') + .replaceAll(obj.address, checkSRS(obj.address, shouldThrow)) + ); } if (this.constructor.name === 'SMTP') { - await onDataSMTP.call(this, raw, session); + // parse the date for SMTP queuing + let date = new Date(headers.getFirst('date')); + if ( + !date || + date.toString() === 'Invalid Date' || + date < ONE_SECOND_AFTER_UNIX_EPOCH || + !_.isDate(date) + ) { + date = new Date(session.arrivalDate); + } + + await onDataSMTP.call(this, raw, session, date); return setImmediate(fn); } diff --git a/helpers/parse-addresses.js b/helpers/parse-addresses.js new file mode 100644 index 000000000..0d93b9c23 --- /dev/null +++ b/helpers/parse-addresses.js @@ -0,0 +1,35 @@ +/** + * Copyright (c) Forward Email LLC + * SPDX-License-Identifier: BUSL-1.1 + */ + +const punycode = require('node:punycode'); + +const _ = require('lodash'); +const addressParser = require('nodemailer/lib/addressparser'); +const addrs = require('email-addresses'); +const isSANB = require('is-string-and-not-blank'); +const { isEmail } = require('validator'); + +function parseAddresses(input) { + if (!isSANB(input)) return []; + + let addresses = addrs.parseAddressList({ input, partial: true }) || []; + + if (addresses.length === 0) + addresses = addrs.parseAddressList({ input }) || []; + + // safeguard + if (addresses.length === 0) addresses = addressParser(input); + + addresses = addresses.filter( + (addr) => + _.isObject(addr) && + isSANB(addr.address) && + isEmail(punycode.toASCII(addr.address), { ignore_max_length: true }) + ); + + return addresses; +} + +module.exports = parseAddresses; diff --git a/helpers/parse-host-from-domain-or-address.js b/helpers/parse-host-from-domain-or-address.js index bf1401614..391596527 100644 --- a/helpers/parse-host-from-domain-or-address.js +++ b/helpers/parse-host-from-domain-or-address.js @@ -7,14 +7,14 @@ const punycode = require('node:punycode'); const { isIP } = require('node:net'); const _ = require('lodash'); -const addressParser = require('nodemailer/lib/addressparser'); const isFQDN = require('is-fqdn'); const isSANB = require('is-string-and-not-blank'); const SMTPError = require('#helpers/smtp-error'); +const parseAddresses = require('#helpers/parse-addresses'); function parseHostFromDomainOrAddress(address) { - const parsedAddresses = addressParser(address); + const parsedAddresses = parseAddresses(address); let domain = address; if ( diff --git a/helpers/parse-username.js b/helpers/parse-username.js index 3e4c29649..d1bdaa200 100644 --- a/helpers/parse-username.js +++ b/helpers/parse-username.js @@ -5,10 +5,10 @@ const punycode = require('node:punycode'); -const addressParser = require('nodemailer/lib/addressparser'); +const parseAddresses = require('#helpers/parse-addresses'); function parseUsername(address) { - ({ address } = addressParser(address)[0]); + ({ address } = parseAddresses(address)[0]); let username = address.includes('+') ? address.split('+')[0] : address.split('@')[0]; diff --git a/helpers/populate-domain-storage.js b/helpers/populate-domain-storage.js new file mode 100644 index 000000000..57328b85d --- /dev/null +++ b/helpers/populate-domain-storage.js @@ -0,0 +1,29 @@ +/** + * Copyright (c) Forward Email LLC + * SPDX-License-Identifier: BUSL-1.1 + */ + +const Domains = require('#models/domains'); +const logger = require('#helpers/logger'); + +async function populateDomainStorage(d, locale) { + if (!d._id) throw new TypeError('_id missing'); + if (d.is_global || d.plan === 'free') return d; + try { + const [storageUsed, storageUsedByAliases, maxQuotaPerAlias] = + await Promise.all([ + Domains.getStorageUsed(d._id, locale), + Domains.getStorageUsed(d._id, locale, true), + Domains.getMaxQuota(d._id) + ]); + d.storage_used = storageUsed; + d.storage_used_by_aliases = storageUsedByAliases; + d.storage_quota = maxQuotaPerAlias; + } catch (err) { + logger.fatal(err); + } + + return d; +} + +module.exports = populateDomainStorage; diff --git a/helpers/process-email.js b/helpers/process-email.js index bf6f2c1ba..dad4f3b8d 100644 --- a/helpers/process-email.js +++ b/helpers/process-email.js @@ -1311,7 +1311,12 @@ async function processEmail({ email, port = 25, resolver, client }) { obj.locale, domain.name, domain.bounce_webhook - ) + `
${parseErr(err)}
`; + ) + + `
${JSON.stringify(
+                  parseErr(err),
+                  null,
+                  2
+                )}
`; await emailHelper({ template: 'alert', message: { diff --git a/helpers/send-pagination-check.js b/helpers/send-pagination-check.js new file mode 100644 index 000000000..a5d415534 --- /dev/null +++ b/helpers/send-pagination-check.js @@ -0,0 +1,49 @@ +/** + * Copyright (c) Forward Email LLC + * SPDX-License-Identifier: BUSL-1.1 + */ + +const ms = require('ms'); + +const config = require('#config'); +const emailHelper = require('#helpers/email'); +const i18n = require('#helpers/i18n'); + +async function sendPaginationCheck(ctx) { + const key = `pagination_check:${ctx.state.user.id}`; + try { + const cache = await ctx.client.get(key); + // return early if cache found + if (cache) return; + await ctx.client.set(key, true, 'PX', ms('90d')); + const link = `${config.urls.web}/${ctx.locale}/api#pagination`; + const subject = i18n.translate('PAGINATION_CHECK_SUBJECT', ctx.locale); + const message = i18n.translate( + 'PAGINATION_CHECK_MESSAGE', + ctx.locale, + link, + link + ); + await emailHelper({ + template: 'alert', + message: { + to: ctx.state.user[config.userFields.fullEmail], + bcc: config.email.message.from, + subject + }, + locals: { + user: ctx.state.user.toObject(), + message + } + }); + } catch (err) { + ctx.logger.fatal(err); + // if an error occurred while sending email then delete cache so it'll retry later + ctx.client + .del(key) + .then() + .catch((err) => ctx.logger.fatal(err)); + } +} + +module.exports = sendPaginationCheck; diff --git a/helpers/set-pagination-headers.js b/helpers/set-pagination-headers.js new file mode 100644 index 000000000..8417fe2b8 --- /dev/null +++ b/helpers/set-pagination-headers.js @@ -0,0 +1,67 @@ +/** + * Copyright (c) Forward Email LLC + * SPDX-License-Identifier: BUSL-1.1 + */ + +const URLParse = require('url-parse'); +const qs = require('qs'); + +// this is a helper function that rewrites the current URL +// to contain an updated querystring value for the page count +function getLink(ctx, page) { + const url = new URLParse(ctx.href, (query) => + qs.parse(query, { ignoreQueryPrefix: true }) + ); + url.query.page = page; + return url.toString((query) => + qs.stringify(query, { addQueryPrefix: true, format: 'RFC1738' }) + ); +} + +// +// set HTTP headers for pagination +// +// +// eslint-disable-next-line max-params +function setPaginationHeaders( + ctx, + pageCount = 1, + currentPage = 1, + size = 1, + itemCount = 0 +) { + // return early if it was not an API request + if (!ctx.api) return; + + // developer and human-friendly easy to parse HTTP pagination headers + ctx.set('X-Page-Count', pageCount); + ctx.set('X-Page-Current', currentPage); + ctx.set('X-Page-Size', size || 1); + ctx.set('X-Item-Count', itemCount); + + // + // Set "Link" HTTP header commonly used by other services for pagination + // This is similar to GitHub (e.g. not all values will be provided if they are not relevant or available, e.g. "next" will not be provided if there is not another page). + // + // + // Link: ; rel="prev", + // ; rel="next", + // ; rel="last", + // ; rel="first" + // (with the values joined by spaces) + // + // NOTE: we wouldn't set this for web requests b/c web request already have "rel=canonical" Link header + // + const links = []; + if (currentPage > 1) + links.push(`<${getLink(ctx, currentPage - 1)}>; rel="prev"`); + if (size > currentPage) + links.push(`<${getLink(ctx, currentPage + 1)}>; rel="next"`); + links.push( + `<${getLink(ctx, size || 1)})>; rel="last"`, + `<${getLink(ctx, 1)})>; rel="first"` + ); + ctx.set('Link', links.join(', ')); +} + +module.exports = setPaginationHeaders; diff --git a/jobs/sync-paid-alias-allowlist.js b/jobs/sync-paid-alias-allowlist.js index 892f2d9d9..7e684283b 100644 --- a/jobs/sync-paid-alias-allowlist.js +++ b/jobs/sync-paid-alias-allowlist.js @@ -6,6 +6,7 @@ // TODO: remove user.email for all users from denylist const { isIP } = require('node:net'); +const punycode = require('node:punycode'); // eslint-disable-next-line import/no-unassigned-import require('#config/env'); @@ -98,11 +99,15 @@ graceful.listen(); } const set = new Set(); - set.add(`${domain.name}`); + set.add(punycode.toASCII(domain.name)); + set.add(domain.name); { // parse root domain const rootDomain = parseRootDomain(domain.name); - if (domain.name !== rootDomain) set.add(rootDomain); + if (domain.name !== rootDomain) { + set.add(rootDomain); + set.add(punycode.toASCII(rootDomain)); + } } for await (const alias of Aliases.find({ @@ -131,21 +136,29 @@ graceful.listen(); if (isFQDN(recipient)) { const domain = recipient.toLowerCase(); set.add(domain); + set.add(punycode.toASCII(domain)); // parse root domain const rootDomain = parseRootDomain(domain); - if (domain !== rootDomain) set.add(domain); + if (domain !== rootDomain) { + set.add(domain); + set.add(punycode.toASCII(domain)); + } } else if (isEmail(recipient)) { // parse domain // const [userPortion, domain] = recipient.split('@'); const [, domain] = recipient.split('@'); // parse root domain set.add(domain); + set.add(punycode.toASCII(domain)); // if (alias.name.startsWith('/') && !/\$\d/.test(userPortion)) // set.add(recipient); // already lowercased (see alias model) // else set.add(recipient); // already lowercased (see alias model) // parse root domain const rootDomain = parseRootDomain(domain); - if (domain !== rootDomain) set.add(domain); + if (domain !== rootDomain) { + set.add(domain); + set.add(punycode.toASCII(domain)); + } } else if (isIP(recipient)) { set.add(recipient); } diff --git a/locales/ar.json b/locales/ar.json index 7ec49c96e..90586a691 100644 --- a/locales/ar.json +++ b/locales/ar.json @@ -10154,5 +10154,104 @@ "Reviews, comparison, screenshots and more for the 80 best email services.": "المراجعات والمقارنة ولقطات الشاشة والمزيد لأفضل 80 خدمة بريد إلكتروني.", "The Missing Email": "البريد الإلكتروني المفقود", "14 Best Private Email Services in 2024": "أفضل 14 خدمة بريد إلكتروني خاصة في 2024", - "Reviews, comparison, screenshots and more for the 14 best private email services.": "المراجعات والمقارنات ولقطات الشاشة والمزيد لأفضل 14 خدمة بريد إلكتروني خاص." + "Reviews, comparison, screenshots and more for the 14 best private email services.": "المراجعات والمقارنات ولقطات الشاشة والمزيد لأفضل 14 خدمة بريد إلكتروني خاص.", + "Notice: API pagination required starting November 1st": "ملاحظة: ترقيم صفحات واجهة برمجة التطبيقات مطلوب اعتبارًا من الأول من نوفمبر", + "Starting November 1st of this year we will be enforcing API pagination on our API endpoints for list domains and list domain aliases. Learn more about our approach to API pagination and how you can opt-in beforehand at %s.": "بدءًا من الأول من نوفمبر من هذا العام، سنطبق ترقيم الصفحات عبر واجهة برمجة التطبيقات على نقاط نهاية واجهة برمجة التطبيقات الخاصة بنا لنطاقات القائمة وأسماء النطاقات المستعارة. تعرف على المزيد حول نهجنا لترقيم الصفحات عبر واجهة برمجة التطبيقات وكيف يمكنك الاشتراك مسبقًا على %s .", + "Alias Contacts (CardDAV)": "جهات اتصال مستعارة (CardDAV)", + "List contacts": "قائمة جهات الاتصال", + "Create contact": "إنشاء جهة اتصال", + "Retrieve contact": "استرجاع جهة الاتصال", + "Update contact": "تحديث جهة الاتصال", + "Delete contact": "حذف جهة الاتصال", + "Alias Calendars (CalDAV)": "تقويمات الأسماء المستعارة (CalDAV)", + "List calendars": "قائمة التقويمات", + "Create calendar": "إنشاء التقويم", + "Retrieve calendar": "استرجاع التقويم", + "Update calendar": "تحديث التقويم", + "Delete calendar": "حذف التقويم", + "Alias Messages (IMAP/POP3)": "رسائل الاسم المستعار (IMAP/POP3)", + "List and search for messages": "قائمة الرسائل والبحث عنها", + "Create message": "إنشاء رسالة", + "Retrieve message": "استرجاع الرسالة", + "Update message": "تحديث الرسالة", + "Delete message": "حذف الرسالة", + "Alias Folders (IMAP/POP3)": "مجلدات الأسماء المستعارة (IMAP/POP3)", + "List folders": "قائمة المجلدات", + "Create folder": "إنشاء مجلد", + "Retrieve folder": "استرجاع المجلد", + "Update folder": "تحديث المجلد", + "Delete folder": "حذف المجلد", + "Copy folder": "نسخ المجلد", + "Outbound Emails": "رسائل البريد الإلكتروني الصادرة", + "Get outbound SMTP email limit": "الحصول على حد البريد الإلكتروني الصادر عبر SMTP", + "List outbound SMTP emails": "قائمة رسائل البريد الإلكتروني الصادرة عبر SMTP", + "Create outbound SMTP email": "إنشاء بريد إلكتروني SMTP صادر", + "Retrieve outbound SMTP email": "استرداد البريد الإلكتروني الصادر SMTP", + "Delete outbound SMTP email": "حذف البريد الإلكتروني الصادر عبر SMTP", + "header (with the exception of": "الرأس (باستثناء", + "Alias Contacts": "جهات الاتصال المستعارة", + "Alias Calendars": "تقويمات الأسماء المستعارة", + "Alias Mailboxes": "صناديق البريد المستعارة", + "which use a": "التي تستخدم", + "generated alias username and password": "تم إنشاء اسم المستخدم وكلمة المرور المستعارة", + "Don't worry – examples are provided below for you if you're not sure what this is.": "لا تقلق - فيما يلي أمثلة لك إذا لم تكن متأكدًا مما يعنيه هذا.", + "As of November 1st, 2024 the API endpoints for": "اعتبارًا من 1 نوفمبر 2024، نقاط نهاية واجهة برمجة التطبيقات لـ", + "will default to": "سوف يكون افتراضيا", + "max results per page. If you would like to opt-in to this behavior early, you can pass": "الحد الأقصى للنتائج لكل صفحة. إذا كنت ترغب في الاشتراك في هذا السلوك مبكرًا، فيمكنك المرور", + "as an additional querystring parameter to the URL for the endpoint query.": "كمعلمة سلسلة استعلام إضافية لعنوان URL لاستعلام نقطة النهاية.", + "Pagination is supported by all API endpoints that list results.": "يتم دعم الترقيم الصفحي من قبل جميع نقاط نهاية واجهة برمجة التطبيقات التي تسرد النتائج.", + "Simply provide the querystring properties": "قم ببساطة بتوفير خصائص سلسلة الاستعلام", + "(and optionally": "(واختياريا", + "The property": "الممتلكات", + "should be a number greater than or equal to": "يجب أن يكون رقمًا أكبر من أو يساوي", + ". If you provide": ". إذا قمت بتوفير", + "(also a number), then the minimum value is": "(أيضًا رقم)، فإن القيمة الدنيا هي", + "and maximum is": "والحد الأقصى هو", + "(unless otherwise noted).": "(ما لم يُذكر خلاف ذلك).", + "Page of results to return. If not specified, the": "صفحة النتائج المراد إرجاعها. إذا لم يتم تحديد ذلك،", + "value will be": "القيمة ستكون", + ". Must be a number greater than or equal to": ". يجب أن يكون رقمًا أكبر من أو يساوي", + "Number of results to return per page. Defaults to": "عدد النتائج التي سيتم إرجاعها لكل صفحة. الافتراضي هو", + "if not specified. Must be a number greater than or equal to": "إذا لم يتم تحديد ذلك، يجب أن يكون الرقم أكبر من أو يساوي", + ", and less than or equal to": "، وأقل من أو يساوي", + "In order to determine whether or not more results are available, we provide these HTTP response headers (which you can parse in order to paginate programmatically):": "لتحديد ما إذا كانت هناك نتائج أخرى متاحة أم لا، فإننا نقدم رؤوس استجابة HTTP التالية (والتي يمكنك تحليلها من أجل تقسيم الصفحات برمجيًا):", + "HTTP Response Header": "رأس استجابة HTTP", + "The total page count available.": "إجمالي عدد الصفحات المتاحة.", + "The current page of results returned (e.g. based off": "الصفحة الحالية للنتائج التي تم إرجاعها (على سبيل المثال، بناءً على", + "querystring parameter).": "معلمات سلسلة الاستعلام).", + "The total number of results in the page returned (e.g. based off": "العدد الإجمالي للنتائج في الصفحة التي تم إرجاعها (على سبيل المثال بناءً على", + "querystring parameter and actual results returned).": "معلمة querystring والنتائج الفعلية التي تم إرجاعها).", + "The total number of items available across all pages.": "العدد الإجمالي للعناصر المتوفرة في جميع الصفحات.", + "We provide a": "نحن نقدم", + "HTTP response header you can parse as shown in the example. This is": "يمكنك تحليل رأس استجابة HTTP كما هو موضح في المثال. هذا هو", + "similar to GitHub": "مشابه لـ GitHub", + "(e.g. not all values will be provided if they are not relevant or available, e.g.": "(على سبيل المثال، لن يتم توفير جميع القيم إذا لم تكن ذات صلة أو متاحة، على سبيل المثال)", + "will not be provided if there is not another page).": "لن يتم توفيرها إذا لم تكن هناك صفحة أخرى).", + "Unlike other API endpoints, these require": "على عكس نقاط نهاية واجهة برمجة التطبيقات الأخرى، تتطلب هذه", + "\"username\" equal to the alias username and \"password\" equal to the alias generated password as Basic Authorization headers.": "\"اسم المستخدم\" يساوي اسم المستخدم المستعار و\"كلمة المرور\" تساوي كلمة المرور المستعارة التي تم إنشاؤها كرؤوس تفويض أساسية.", + "This endpoint section is a work in progress and will be released (hopefully) in 2024. In the interim please use an IMAP client from the \"Apps\" dropdown in the navigation of our website.": "يعد قسم نقطة النهاية هذا عملاً قيد التقدم وسيتم إصداره (نأمل ذلك) في عام 2024. وفي غضون ذلك، يُرجى استخدام عميل IMAP من القائمة المنسدلة \"التطبيقات\" في شريط التنقل بموقعنا على الويب.", + "CardDAV support is not yet available, follow this discussion on GitHub for updates": "لم يتوفر دعم CardDAV بعد، تابع هذه المناقشة على GitHub للحصول على التحديثات", + "Please ensure that you have followed setup instructions for your domain.": "يرجى التأكد من أنك اتبعت تعليمات الإعداد الخاصة بنطاقك.", + "These instructions can be found in our FAQ section": "يمكن العثور على هذه التعليمات في قسم الأسئلة الشائعة لدينا", + "Do you support receiving email with IMAP?": "هل تدعم تلقي البريد الإلكتروني باستخدام IMAP؟", + "This will": "هذا سوف", + "send an email – it will only simply add the message to your mailbox folder (e.g. this is similar to the IMAP": "إرسال بريد إلكتروني - سيؤدي ذلك ببساطة إلى إضافة الرسالة إلى مجلد صندوق البريد الخاص بك (على سبيل المثال، هذا مشابه لبروتوكول IMAP", + "command). If you would like to send an email, then see": "إذا كنت ترغب في إرسال بريد إلكتروني، فراجع", + "below. After creating the outbound SMTP email, then you can append a copy of it using this endpoint to your alias' mailbox for storage purposes.": "بعد إنشاء بريد SMTP الصادر، يمكنك بعد ذلك إضافة نسخة منه باستخدام هذه النقطة النهائية إلى صندوق بريد الاسم المستعار الخاص بك لأغراض التخزين.", + "Folder endpoints with a folder's path": "نقاط نهاية المجلد مع مسار المجلد", + "as their endpoint are interchangeable with a folder's ID": "نظرًا لأن نقطة النهاية الخاصة بهم قابلة للتبديل مع معرف المجلد", + ". This means you can refer to the folder by either its": "هذا يعني أنه يمكنك الرجوع إلى المجلد إما عن طريق اسمه أو عن طريق", + "These instructions can be found at": "يمكن العثور على هذه التعليمات في", + "Note that this endpoint does not return property values for an email's": "لاحظ أن نقطة النهاية هذه لا تقوم بإرجاع قيم الخصائص لرسائل البريد الإلكتروني", + "Sort by a specific field (prefix with a single hyphen": "الفرز حسب حقل معين (بادئة بواصلة واحدة)", + "to sort in the reverse direction of that field). Defaults to": "للفرز في الاتجاه المعاكس لهذا الحقل). الافتراضي هو", + "if not set.": "إذا لم يتم ضبطه.", + "for more insight": "لمزيد من المعرفة", + "as their endpoint are interchangeable with a domain's ID": "نظرًا لأن نقطة النهاية الخاصة بهم قابلة للتبديل مع معرف المجال", + "as an additional querystring parameter to the URL for the endpoint query. See": "كمعلمة سلسلة استعلام إضافية لعنوان URL لاستعلام نقطة النهاية. راجع", + "(\"SRS\") address here to protect against spoofing with our SRS domain name. We also check the recipient against our": "(\"SRS\") هنا للحماية من التزييف باستخدام اسم نطاق SRS الخاص بنا. كما نتحقق من المستلم وفقًا لـ", + "- this is only applicable for outbound SMTP and correlates to the email ID stored in My Account → Emails": "- ينطبق هذا فقط على SMTP الصادر ويرتبط بمعرف البريد الإلكتروني المخزن في حسابي → رسائل البريد الإلكتروني", + "Bank Transfer": "التحويل البنكي", + "Domestic Wire Transfer (Enterprise)": "التحويل البنكي المحلي (المؤسسي)", + "International Wire Transfer (Enterprise)": "التحويل البنكي الدولي (المؤسسات)" } \ No newline at end of file diff --git a/locales/cs.json b/locales/cs.json index a58da506c..bd83c4163 100644 --- a/locales/cs.json +++ b/locales/cs.json @@ -10154,5 +10154,104 @@ "Reviews, comparison, screenshots and more for the 80 best email services.": "Recenze, srovnání, snímky obrazovky a další pro 80 nejlepších e-mailových služeb.", "The Missing Email": "Chybějící e-mail", "14 Best Private Email Services in 2024": "14 nejlepších soukromých e-mailových služeb v 2024", - "Reviews, comparison, screenshots and more for the 14 best private email services.": "Recenze, srovnání, snímky obrazovky a další pro 14 nejlepších soukromých e-mailových služeb." + "Reviews, comparison, screenshots and more for the 14 best private email services.": "Recenze, srovnání, snímky obrazovky a další pro 14 nejlepších soukromých e-mailových služeb.", + "Notice: API pagination required starting November 1st": "Upozornění: Od 1. listopadu je vyžadováno stránkování API", + "Starting November 1st of this year we will be enforcing API pagination on our API endpoints for list domains and list domain aliases. Learn more about our approach to API pagination and how you can opt-in beforehand at %s.": "Počínaje 1. listopadem tohoto roku budeme vynucovat stránkování API na našich koncových bodech API pro seznam domén a seznam aliasů domén. Zjistěte více o našem přístupu k stránkování API a o tom, jak se můžete předem přihlásit na %s .", + "Alias Contacts (CardDAV)": "Alias Contacts (CardDAV)", + "List contacts": "Seznam kontaktů", + "Create contact": "Vytvořte kontakt", + "Retrieve contact": "Získat kontakt", + "Update contact": "Aktualizujte kontakt", + "Delete contact": "Smazat kontakt", + "Alias Calendars (CalDAV)": "Aliasové kalendáře (CalDAV)", + "List calendars": "Seznam kalendářů", + "Create calendar": "Vytvořit kalendář", + "Retrieve calendar": "Načíst kalendář", + "Update calendar": "Aktualizovat kalendář", + "Delete calendar": "Smazat kalendář", + "Alias Messages (IMAP/POP3)": "Aliasové zprávy (IMAP/POP3)", + "List and search for messages": "Seznam a vyhledávání zpráv", + "Create message": "Vytvořit zprávu", + "Retrieve message": "Načíst zprávu", + "Update message": "Aktualizovat zprávu", + "Delete message": "Smazat zprávu", + "Alias Folders (IMAP/POP3)": "Alias složky (IMAP/POP3)", + "List folders": "Seznam složek", + "Create folder": "Vytvořit složku", + "Retrieve folder": "Načíst složku", + "Update folder": "Aktualizovat složku", + "Delete folder": "Smazat složku", + "Copy folder": "Kopírovat složku", + "Outbound Emails": "Odchozí e-maily", + "Get outbound SMTP email limit": "Získejte limit odchozích e-mailů SMTP", + "List outbound SMTP emails": "Seznam odchozích e-mailů SMTP", + "Create outbound SMTP email": "Vytvořte odchozí e-mail SMTP", + "Retrieve outbound SMTP email": "Načíst odchozí e-maily SMTP", + "Delete outbound SMTP email": "Smazat odchozí e-mail SMTP", + "header (with the exception of": "záhlaví (s výjimkou", + "Alias Contacts": "Alias Kontakty", + "Alias Calendars": "Alias kalendáře", + "Alias Mailboxes": "Alias poštovní schránky", + "which use a": "které používají a", + "generated alias username and password": "vygenerovaný alias uživatelské jméno a heslo", + "Don't worry – examples are provided below for you if you're not sure what this is.": "Nemějte obavy – níže jsou uvedeny příklady, pokud si nejste jisti, co to je.", + "As of November 1st, 2024 the API endpoints for": "Od 1. listopadu 2024 budou koncové body API pro", + "will default to": "bude výchozí", + "max results per page. If you would like to opt-in to this behavior early, you can pass": "maximální počet výsledků na stránku. Pokud byste se chtěli k tomuto chování přihlásit dříve, můžete projít", + "as an additional querystring parameter to the URL for the endpoint query.": "jako další parametr querystring k URL pro dotaz na koncový bod.", + "Pagination is supported by all API endpoints that list results.": "Stránkování je podporováno všemi koncovými body API, které vypisují výsledky.", + "Simply provide the querystring properties": "Jednoduše zadejte vlastnosti querystringu", + "(and optionally": "(a volitelně", + "The property": "Nemovitost", + "should be a number greater than or equal to": "by mělo být číslo větší nebo rovné", + ". If you provide": ". Pokud poskytnete", + "(also a number), then the minimum value is": "(také číslo), pak je minimální hodnota", + "and maximum is": "a maximum je", + "(unless otherwise noted).": "(pokud není uvedeno jinak).", + "Page of results to return. If not specified, the": "Stránka s výsledky, která se má vrátit. Pokud není uvedeno,", + "value will be": "hodnota bude", + ". Must be a number greater than or equal to": ". Musí být číslo větší nebo rovno", + "Number of results to return per page. Defaults to": "Počet výsledků, které se mají vrátit na stránku. Výchozí na", + "if not specified. Must be a number greater than or equal to": "není-li uvedeno. Musí být číslo větší nebo rovno", + ", and less than or equal to": "a menší nebo rovno", + "In order to determine whether or not more results are available, we provide these HTTP response headers (which you can parse in order to paginate programmatically):": "Abychom zjistili, zda je nebo není k dispozici více výsledků, poskytujeme tato záhlaví odpovědí HTTP (která můžete analyzovat, abyste je mohli programově stránkovat):", + "HTTP Response Header": "Hlavička odpovědi HTTP", + "The total page count available.": "Celkový počet dostupných stránek.", + "The current page of results returned (e.g. based off": "Vrátila se aktuální stránka výsledků (např. na základě", + "querystring parameter).": "parametry řetězce dotazů).", + "The total number of results in the page returned (e.g. based off": "Celkový počet výsledků na stránce vrácených (např. na základě", + "querystring parameter and actual results returned).": "dotazovací řetězec a vrácené skutečné výsledky).", + "The total number of items available across all pages.": "Celkový počet položek dostupných na všech stránkách.", + "We provide a": "Poskytujeme a", + "HTTP response header you can parse as shown in the example. This is": "Hlavičku odpovědi HTTP můžete analyzovat, jak je znázorněno v příkladu. Tohle je", + "similar to GitHub": "podobně jako GitHub", + "(e.g. not all values will be provided if they are not relevant or available, e.g.": "(např. nebudou poskytnuty všechny hodnoty, pokud nejsou relevantní nebo dostupné, např.", + "will not be provided if there is not another page).": "nebudou poskytnuty, pokud neexistuje jiná stránka).", + "Unlike other API endpoints, these require": "Na rozdíl od jiných koncových bodů API tyto vyžadují", + "\"username\" equal to the alias username and \"password\" equal to the alias generated password as Basic Authorization headers.": "„username“ se rovná aliasu uživatelského jména a „heslo“ se rovná heslu vygenerovanému aliasem jako hlavičky základní autorizace.", + "This endpoint section is a work in progress and will be released (hopefully) in 2024. In the interim please use an IMAP client from the \"Apps\" dropdown in the navigation of our website.": "Tato sekce koncového bodu je ve vývoji a bude vydána (doufejme) v roce 2024. Mezitím prosím používejte klienta IMAP z rozevíracího seznamu „Aplikace“ v navigaci na našem webu.", + "CardDAV support is not yet available, follow this discussion on GitHub for updates": "Podpora CardDAV zatím není k dispozici, aktualizace najdete v této diskuzi na GitHubu", + "Please ensure that you have followed setup instructions for your domain.": "Ujistěte se, že jste postupovali podle pokynů pro nastavení vaší domény.", + "These instructions can be found in our FAQ section": "Tyto pokyny naleznete v naší sekci FAQ", + "Do you support receiving email with IMAP?": "Podporujete přijímání e-mailů pomocí protokolu IMAP?", + "This will": "Toto bude", + "send an email – it will only simply add the message to your mailbox folder (e.g. this is similar to the IMAP": "odeslat e-mail – pouze jednoduše přidá zprávu do složky vaší poštovní schránky (např. je to podobné jako IMAP", + "command). If you would like to send an email, then see": "příkaz). Pokud chcete poslat email, tak viz", + "below. After creating the outbound SMTP email, then you can append a copy of it using this endpoint to your alias' mailbox for storage purposes.": "níže. Po vytvoření odchozího e-mailu SMTP můžete připojit jeho kopii pomocí tohoto koncového bodu do poštovní schránky svého aliasu pro účely úložiště.", + "Folder endpoints with a folder's path": "Koncové body složky s cestou ke složce", + "as their endpoint are interchangeable with a folder's ID": "protože jejich koncový bod je zaměnitelný s ID složky", + ". This means you can refer to the folder by either its": ". To znamená, že můžete odkazovat na složku buď její", + "These instructions can be found at": "Tyto pokyny naleznete na", + "Note that this endpoint does not return property values for an email's": "Všimněte si, že tento koncový bod nevrací hodnoty vlastností pro e-maily", + "Sort by a specific field (prefix with a single hyphen": "Seřadit podle konkrétního pole (předpona s jednou pomlčkou", + "to sort in the reverse direction of that field). Defaults to": "řazení v opačném směru tohoto pole). Výchozí na", + "if not set.": "pokud není nastaveno.", + "for more insight": "pro větší přehled", + "as their endpoint are interchangeable with a domain's ID": "protože jejich koncový bod je zaměnitelný s ID domény", + "as an additional querystring parameter to the URL for the endpoint query. See": "jako další parametr řetězce dotazu k adrese URL pro dotaz na koncový bod. Vidět", + "(\"SRS\") address here to protect against spoofing with our SRS domain name. We also check the recipient against our": "(\"SRS\") adresa zde pro ochranu před spoofingem s názvem naší domény SRS. Také kontrolujeme příjemce proti našim", + "- this is only applicable for outbound SMTP and correlates to the email ID stored in My Account → Emails": "- to platí pouze pro odchozí SMTP a souvisí s e-mailovým ID uloženým v Můj účet → E-maily", + "Bank Transfer": "Bankovní převod", + "Domestic Wire Transfer (Enterprise)": "Domácí bankovní převod (podnikové)", + "International Wire Transfer (Enterprise)": "Mezinárodní bankovní převod (podnik)" } \ No newline at end of file diff --git a/locales/da.json b/locales/da.json index 9936411aa..762a1bec0 100644 --- a/locales/da.json +++ b/locales/da.json @@ -7124,5 +7124,105 @@ "Reviews, comparison, screenshots and more for the 80 best email services.": "Anmeldelser, sammenligning, skærmbilleder og mere for de 80 bedste e-mail-tjenester.", "The Missing Email": "Den manglende e-mail", "14 Best Private Email Services in 2024": "14 bedste private e-mail-tjenester i 2024", - "Reviews, comparison, screenshots and more for the 14 best private email services.": "Anmeldelser, sammenligning, skærmbilleder og mere for de 14 bedste private e-mail-tjenester." + "Reviews, comparison, screenshots and more for the 14 best private email services.": "Anmeldelser, sammenligning, skærmbilleder og mere for de 14 bedste private e-mail-tjenester.", + "Notice: API pagination required starting November 1st": "Bemærk: API-paginering påkrævet fra den 1. november", + "Starting November 1st of this year we will be enforcing API pagination on our API endpoints for list domains and list domain aliases. Learn more about our approach to API pagination and how you can opt-in beforehand at %s.": "Fra den 1. november i år vil vi håndhæve API-paginering på vores API-endepunkter for listedomæner og listedomænealiasser. Lær mere om vores tilgang til API-paginering, og hvordan du kan tilmelde dig på forhånd på %s .", + "Alias Contacts (CardDAV)": "Alias-kontakter (CardDAV)", + "List contacts": "Liste kontakter", + "Create contact": "Opret kontakt", + "Retrieve contact": "Hent kontakt", + "Update contact": "Opdater kontakt", + "Delete contact": "Slet kontakt", + "Alias Calendars (CalDAV)": "Alias kalendere (CalDAV)", + "List calendars": "Liste kalendere", + "Create calendar": "Opret kalender", + "Retrieve calendar": "Hent kalender", + "Update calendar": "Opdater kalender", + "Delete calendar": "Slet kalender", + "Alias Messages (IMAP/POP3)": "Aliasmeddelelser (IMAP/POP3)", + "List and search for messages": "Liste og søg efter beskeder", + "Create message": "Opret besked", + "Retrieve message": "Hent besked", + "Update message": "Opdater besked", + "Delete message": "Slet besked", + "Alias Folders (IMAP/POP3)": "Aliasmapper (IMAP/POP3)", + "List folders": "Liste mapper", + "Create folder": "Opret mappe", + "Retrieve folder": "Hent mappe", + "Update folder": "Opdater mappe", + "Delete folder": "Slet mappe", + "Copy folder": "Kopiér mappe", + "Outbound Emails": "Udgående e-mails", + "Get outbound SMTP email limit": "Få udgående SMTP-e-mail-grænse", + "List outbound SMTP emails": "Liste udgående SMTP-e-mails", + "Create outbound SMTP email": "Opret udgående SMTP-e-mail", + "Retrieve outbound SMTP email": "Hent udgående SMTP-e-mail", + "Delete outbound SMTP email": "Slet udgående SMTP-e-mail", + "header (with the exception of": "header (med undtagelse af", + "Alias Contacts": "Alias kontakter", + "Alias Calendars": "Alias kalendere", + "Alias Mailboxes": "Alias postkasser", + "which use a": "som bruger en", + "generated alias username and password": "genereret alias brugernavn og adgangskode", + "Don't worry – examples are provided below for you if you're not sure what this is.": "Bare rolig – eksempler er givet nedenfor til dig, hvis du ikke er sikker på, hvad det er.", + "As of November 1st, 2024 the API endpoints for": "Fra den 1. november 2024 er API-endepunkterne for", + "will default to": "vil som standard være", + "max results per page. If you would like to opt-in to this behavior early, you can pass": "max resultater pr. side. Hvis du gerne vil tilmelde dig denne adfærd tidligt, kan du bestå", + "as an additional querystring parameter to the URL for the endpoint query.": "som en ekstra querystring-parameter til URL'en for slutpunktsforespørgslen.", + "Pagination is supported by all API endpoints that list results.": "Sideinddeling understøttes af alle API-endepunkter, der viser resultater.", + "Simply provide the querystring properties": "Angiv blot forespørgselsstrengegenskaberne", + "(and optionally": "(og eventuelt", + "The property": "Ejendommen", + "should be a number greater than or equal to": "skal være et tal større end eller lig med", + ". If you provide": ". Hvis du giver", + "(also a number), then the minimum value is": "(også et tal), så er minimumsværdien", + "and maximum is": "og maksimum er", + "(unless otherwise noted).": "(medmindre andet er angivet).", + "Page of results to return. If not specified, the": "Side med resultater, der skal returneres. Hvis det ikke er angivet, skal", + "value will be": "værdi vil være", + ". Must be a number greater than or equal to": ". Skal være et tal større end eller lig med", + "Number of results to return per page. Defaults to": "Antal resultater, der skal returneres pr. side. Standard til", + "if not specified. Must be a number greater than or equal to": "hvis ikke specificeret. Skal være et tal større end eller lig med", + ", and less than or equal to": ", og mindre end eller lig med", + "In order to determine whether or not more results are available, we provide these HTTP response headers (which you can parse in order to paginate programmatically):": "For at afgøre, om flere resultater er tilgængelige eller ej, leverer vi disse HTTP-svarheaders (som du kan parse for at paginere programmatisk):", + "HTTP Response Header": "HTTP Response Header", + "The total page count available.": "Det samlede antal tilgængelige sider.", + "The current page of results returned (e.g. based off": "Den aktuelle side med resultater returneret (f.eks. baseret på", + "querystring parameter).": "forespørgselsstrengparametre).", + "The total number of results in the page returned (e.g. based off": "Det samlede antal resultater på siden returneret (f.eks. baseret på off", + "querystring parameter and actual results returned).": "querystring parameter og faktiske resultater returneret).", + "The total number of items available across all pages.": "Det samlede antal varer, der er tilgængelige på alle sider.", + "We provide a": "Vi leverer en", + "HTTP response header you can parse as shown in the example. This is": "HTTP-svar header du kan parse som vist i eksemplet. Dette er", + "similar to GitHub": "ligner GitHub", + "(e.g. not all values will be provided if they are not relevant or available, e.g.": "(f.eks. vil ikke alle værdier blive angivet, hvis de ikke er relevante eller tilgængelige, f.eks.", + "will not be provided if there is not another page).": "vil ikke blive leveret, hvis der ikke er en anden side).", + "Unlike other API endpoints, these require": "I modsætning til andre API-endepunkter kræver disse", + "\"username\" equal to the alias username and \"password\" equal to the alias generated password as Basic Authorization headers.": "\"brugernavn\" svarende til aliasbrugernavnet og \"adgangskode\" svarende til den aliasgenererede adgangskode som Basic Authorization-headers.", + "This endpoint section is a work in progress and will be released (hopefully) in 2024. In the interim please use an IMAP client from the \"Apps\" dropdown in the navigation of our website.": "Denne endepunktssektion er et igangværende arbejde og vil blive frigivet (forhåbentlig) i 2024. I mellemtiden bedes du bruge en IMAP-klient fra rullemenuen \"Apps\" i navigationen på vores hjemmeside.", + "CardDAV support is not yet available, follow this discussion on GitHub for updates": "CardDAV-support er endnu ikke tilgængelig, følg denne diskussion på GitHub for opdateringer", + "Coming soon": "Kommer snart", + "Please ensure that you have followed setup instructions for your domain.": "Sørg for, at du har fulgt opsætningsinstruktionerne for dit domæne.", + "These instructions can be found in our FAQ section": "Disse instruktioner kan findes i vores FAQ-sektion", + "Do you support receiving email with IMAP?": "Understøtter du modtagelse af e-mail med IMAP?", + "This will": "Dette vil", + "send an email – it will only simply add the message to your mailbox folder (e.g. this is similar to the IMAP": "send en e-mail - det vil kun tilføje beskeden til din postkassemappe (det ligner f.eks. IMAP'en", + "command). If you would like to send an email, then see": "kommando). Hvis du gerne vil sende en e-mail, så se", + "below. After creating the outbound SMTP email, then you can append a copy of it using this endpoint to your alias' mailbox for storage purposes.": "under. Når du har oprettet den udgående SMTP-e-mail, kan du tilføje en kopi af den ved hjælp af dette slutpunkt til dit alias' postkasse til opbevaringsformål.", + "Folder endpoints with a folder's path": "Mappeslutpunkter med en mappes sti", + "as their endpoint are interchangeable with a folder's ID": "da deres endepunkt kan udskiftes med en mappes ID", + ". This means you can refer to the folder by either its": ". Dette betyder, at du kan henvise til mappen ved enten dens", + "These instructions can be found at": "Disse instruktioner kan findes på", + "Note that this endpoint does not return property values for an email's": "Bemærk, at dette slutpunkt ikke returnerer egenskabsværdier for en e-mail", + "Sort by a specific field (prefix with a single hyphen": "Sorter efter et bestemt felt (præfiks med en enkelt bindestreg", + "to sort in the reverse direction of that field). Defaults to": "at sortere i den modsatte retning af det pågældende felt). Standard til", + "if not set.": "hvis ikke indstillet.", + "for more insight": "for mere indsigt", + "as their endpoint are interchangeable with a domain's ID": "da deres endepunkt kan udskiftes med et domænes ID", + "as an additional querystring parameter to the URL for the endpoint query. See": "som en ekstra querystring-parameter til URL'en for slutpunktsforespørgslen. Se", + "(\"SRS\") address here to protect against spoofing with our SRS domain name. We also check the recipient against our": "(\"SRS\") adresse her for at beskytte mod spoofing med vores SRS-domænenavn. Vi tjekker også modtageren op mod vores", + "- this is only applicable for outbound SMTP and correlates to the email ID stored in My Account → Emails": "- dette gælder kun for udgående SMTP og korrelerer med det e-mail-id, der er gemt i Min konto → E-mails", + "Bank Transfer": "Bankoverførsel", + "Domestic Wire Transfer (Enterprise)": "Indenlandsk bankoverførsel (virksomhed)", + "International Wire Transfer (Enterprise)": "International bankoverførsel (Enterprise)" } \ No newline at end of file diff --git a/locales/de.json b/locales/de.json index fb6d2f9c3..29e7db63b 100644 --- a/locales/de.json +++ b/locales/de.json @@ -9192,5 +9192,105 @@ "Reviews, comparison, screenshots and more for the 80 best email services.": "Testberichte, Vergleiche, Screenshots und mehr zu den 80 besten E-Mail-Diensten.", "The Missing Email": "Die fehlende E-Mail", "14 Best Private Email Services in 2024": "Die 14 besten privaten E-Mail-Dienste im 2024", - "Reviews, comparison, screenshots and more for the 14 best private email services.": "Testberichte, Vergleiche, Screenshots und mehr zu den 14 besten privaten E-Mail-Diensten." + "Reviews, comparison, screenshots and more for the 14 best private email services.": "Testberichte, Vergleiche, Screenshots und mehr zu den 14 besten privaten E-Mail-Diensten.", + "Notice: API pagination required starting November 1st": "Hinweis: API-Paginierung ab 1. November erforderlich", + "Starting November 1st of this year we will be enforcing API pagination on our API endpoints for list domains and list domain aliases. Learn more about our approach to API pagination and how you can opt-in beforehand at %s.": "Ab dem 1. November dieses Jahres erzwingen wir die API-Paginierung an unseren API-Endpunkten für Listendomänen und Listendomänen-Aliase. Erfahren Sie mehr über unseren Ansatz zur API-Paginierung und wie Sie sich vorab anmelden können unter %s .", + "Alias Contacts (CardDAV)": "Alias-Kontakte (CardDAV)", + "List contacts": "Kontakte auflisten", + "Create contact": "Kontakt erstellen", + "Retrieve contact": "Kontakt abrufen", + "Update contact": "Kontakt aktualisieren", + "Delete contact": "Kontakt löschen", + "Alias Calendars (CalDAV)": "Alias-Kalender (CalDAV)", + "List calendars": "Kalender auflisten", + "Create calendar": "Kalender erstellen", + "Retrieve calendar": "Kalender abrufen", + "Update calendar": "Kalender aktualisieren", + "Delete calendar": "Kalender löschen", + "Alias Messages (IMAP/POP3)": "Alias-Nachrichten (IMAP/POP3)", + "List and search for messages": "Auflisten und Suchen von Nachrichten", + "Create message": "Nachricht erstellen", + "Retrieve message": "Nachricht abrufen", + "Update message": "Update-Meldung", + "Delete message": "Nachricht löschen", + "Alias Folders (IMAP/POP3)": "Alias-Ordner (IMAP/POP3)", + "List folders": "Ordner auflisten", + "Create folder": "Ordner erstellen", + "Retrieve folder": "Ordner abrufen", + "Update folder": "Ordner aktualisieren", + "Delete folder": "Ordner löschen", + "Copy folder": "Ordner kopieren", + "Outbound Emails": "Ausgehende E-Mails", + "Get outbound SMTP email limit": "Limit für ausgehende SMTP-E-Mails abrufen", + "List outbound SMTP emails": "Auflisten ausgehender SMTP-E-Mails", + "Create outbound SMTP email": "Ausgehende SMTP-E-Mail erstellen", + "Retrieve outbound SMTP email": "Ausgehende SMTP-E-Mails abrufen", + "Delete outbound SMTP email": "Ausgehende SMTP-E-Mails löschen", + "header (with the exception of": "Header (mit Ausnahme von", + "Alias Contacts": "Alias-Kontakte", + "Alias Calendars": "Alias Kalender", + "Alias Mailboxes": "Alias-Postfächer", + "which use a": "die eine", + "generated alias username and password": "generierter Alias-Benutzername und Passwort", + "Don't worry – examples are provided below for you if you're not sure what this is.": "Keine Sorge – wenn Sie nicht sicher sind, was das ist, finden Sie weiter unten Beispiele.", + "As of November 1st, 2024 the API endpoints for": "Ab dem 1. November 2024 sind die API-Endpunkte für", + "will default to": "wird standardmäßig", + "max results per page. If you would like to opt-in to this behavior early, you can pass": "max Ergebnisse pro Seite. Wenn Sie sich frühzeitig für dieses Verhalten entscheiden möchten, können Sie", + "as an additional querystring parameter to the URL for the endpoint query.": "als zusätzlicher Abfragezeichenfolgenparameter zur URL für die Endpunktabfrage.", + "Pagination is supported by all API endpoints that list results.": "Die Paginierung wird von allen API-Endpunkten unterstützt, die Ergebnisse auflisten.", + "Simply provide the querystring properties": "Geben Sie einfach die Querystring-Eigenschaften an", + "(and optionally": "(und optional", + "The property": "Das Anwesen", + "should be a number greater than or equal to": "sollte eine Zahl größer oder gleich sein", + ". If you provide": "Wenn Sie angeben", + "(also a number), then the minimum value is": "(ebenfalls eine Zahl), dann ist der Mindestwert", + "and maximum is": "und das Maximum ist", + "(unless otherwise noted).": "(sofern nicht anders angegeben).", + "Page of results to return. If not specified, the": "Seite mit den zurückzugebenden Ergebnissen. Wenn nicht angegeben,", + "value will be": "Wert wird", + ". Must be a number greater than or equal to": ". Muss eine Zahl größer oder gleich sein", + "Number of results to return per page. Defaults to": "Anzahl der Ergebnisse, die pro Seite zurückgegeben werden sollen. Standardmäßig", + "if not specified. Must be a number greater than or equal to": "wenn nicht angegeben. Muss eine Zahl größer oder gleich sein", + ", and less than or equal to": "und kleiner oder gleich", + "In order to determine whether or not more results are available, we provide these HTTP response headers (which you can parse in order to paginate programmatically):": "Um zu ermitteln, ob weitere Ergebnisse verfügbar sind oder nicht, stellen wir diese HTTP-Antwortheader bereit (die Sie analysieren können, um programmgesteuert eine Paginierung vorzunehmen):", + "HTTP Response Header": "HTTP-Antwortheader", + "The total page count available.": "Die insgesamt verfügbare Seitenzahl.", + "The current page of results returned (e.g. based off": "Die aktuelle Seite mit den zurückgegebenen Ergebnissen (z. B. basierend auf", + "querystring parameter).": "Querystring-Parameter).", + "The total number of results in the page returned (e.g. based off": "Die Gesamtzahl der Ergebnisse auf der zurückgegebenen Seite (z. B. basierend auf", + "querystring parameter and actual results returned).": "Abfragezeichenfolgenparameter und tatsächlich zurückgegebene Ergebnisse).", + "The total number of items available across all pages.": "Die Gesamtzahl der auf allen Seiten verfügbaren Elemente.", + "We provide a": "Wir bieten eine", + "HTTP response header you can parse as shown in the example. This is": "HTTP-Antwortheader, den Sie wie im Beispiel gezeigt analysieren können. Dies ist", + "similar to GitHub": "ähnlich wie GitHub", + "(e.g. not all values will be provided if they are not relevant or available, e.g.": "(z. B. werden nicht alle Werte bereitgestellt, wenn sie nicht relevant oder verfügbar sind, z. B.", + "will not be provided if there is not another page).": "wird nicht bereitgestellt, wenn keine andere Seite vorhanden ist).", + "Unlike other API endpoints, these require": "Im Gegensatz zu anderen API-Endpunkten erfordern diese", + "\"username\" equal to the alias username and \"password\" equal to the alias generated password as Basic Authorization headers.": "„Benutzername“ entspricht dem Alias-Benutzernamen und „Passwort“ entspricht dem vom Alias generierten Passwort als Header für die grundlegende Autorisierung.", + "This endpoint section is a work in progress and will be released (hopefully) in 2024. In the interim please use an IMAP client from the \"Apps\" dropdown in the navigation of our website.": "Dieser Endpunktabschnitt ist in Arbeit und wird (hoffentlich) im Jahr 2024 veröffentlicht. Verwenden Sie in der Zwischenzeit bitte einen IMAP-Client aus dem Dropdown-Menü „Apps“ in der Navigation unserer Website.", + "CardDAV support is not yet available, follow this discussion on GitHub for updates": "CardDAV-Unterstützung ist noch nicht verfügbar, folgen Sie dieser Diskussion auf GitHub für Updates", + "Coming soon": "Demnächst verfügbar", + "Please ensure that you have followed setup instructions for your domain.": "Bitte stellen Sie sicher, dass Sie die Einrichtungsanweisungen für Ihre Domäne befolgt haben.", + "These instructions can be found in our FAQ section": "Diese Anleitung finden Sie in unserem FAQ-Bereich", + "Do you support receiving email with IMAP?": "Unterstützen Sie den E-Mail-Empfang mit IMAP?", + "This will": "Dies wird", + "send an email – it will only simply add the message to your mailbox folder (e.g. this is similar to the IMAP": "eine E-Mail senden – es wird nur einfach die Nachricht zu Ihrem Postfachordner hinzufügen (z.B. dies ist ähnlich wie die IMAP", + "command). If you would like to send an email, then see": "Befehl). Wenn Sie eine E-Mail senden möchten, lesen Sie", + "below. After creating the outbound SMTP email, then you can append a copy of it using this endpoint to your alias' mailbox for storage purposes.": "unten. Nachdem Sie die ausgehende SMTP-E-Mail erstellt haben, können Sie mit diesem Endpunkt eine Kopie davon zur Speicherung an das Postfach Ihres Alias anhängen.", + "Folder endpoints with a folder's path": "Ordnerendpunkte mit dem Pfad eines Ordners", + "as their endpoint are interchangeable with a folder's ID": "da ihr Endpunkt mit der ID eines Ordners austauschbar ist", + ". This means you can refer to the folder by either its": ". Das bedeutet, dass Sie den Ordner entweder über seine", + "These instructions can be found at": "Diese Anleitung finden Sie unter", + "Note that this endpoint does not return property values for an email's": "Beachten Sie, dass dieser Endpunkt keine Eigenschaftswerte für die", + "Sort by a specific field (prefix with a single hyphen": "Sortieren nach einem bestimmten Feld (Präfix mit einem einzelnen Bindestrich", + "to sort in the reverse direction of that field). Defaults to": "um in umgekehrter Richtung des Feldes zu sortieren). Standardmäßig", + "if not set.": "wenn nicht festgelegt.", + "for more insight": "für mehr Einblick", + "as their endpoint are interchangeable with a domain's ID": "da ihr Endpunkt mit der ID einer Domäne austauschbar ist", + "as an additional querystring parameter to the URL for the endpoint query. See": "als zusätzlicher Abfrageparameter zur URL für die Endpunktabfrage. Siehe", + "(\"SRS\") address here to protect against spoofing with our SRS domain name. We also check the recipient against our": "(\"SRS\")-Adresse hier, um vor Spoofing mit unserem SRS-Domänennamen zu schützen. Wir überprüfen den Empfänger auch anhand unserer", + "- this is only applicable for outbound SMTP and correlates to the email ID stored in My Account → Emails": "- dies gilt nur für ausgehendes SMTP und korreliert mit der E-Mail-ID, die unter Mein Konto → E-Mails gespeichert ist", + "Bank Transfer": "Banküberweisung", + "Domestic Wire Transfer (Enterprise)": "Inlandsüberweisung (Unternehmen)", + "International Wire Transfer (Enterprise)": "Internationale elektronische Überweisung (Unternehmen)" } \ No newline at end of file diff --git a/locales/en.json b/locales/en.json index 6a857892a..0f05199e7 100644 --- a/locales/en.json +++ b/locales/en.json @@ -9885,5 +9885,104 @@ "Reviews, comparison, screenshots and more for the 80 best email services.": "Reviews, comparison, screenshots and more for the 80 best email services.", "The Missing Email": "The Missing Email", "14 Best Private Email Services in 2024": "14 Best Private Email Services in 2024", - "Reviews, comparison, screenshots and more for the 14 best private email services.": "Reviews, comparison, screenshots and more for the 14 best private email services." + "Reviews, comparison, screenshots and more for the 14 best private email services.": "Reviews, comparison, screenshots and more for the 14 best private email services.", + "Notice: API pagination required starting November 1st": "Notice: API pagination required starting November 1st", + "Starting November 1st of this year we will be enforcing API pagination on our API endpoints for list domains and list domain aliases. Learn more about our approach to API pagination and how you can opt-in beforehand at %s.": "Starting November 1st of this year we will be enforcing API pagination on our API endpoints for list domains and list domain aliases. Learn more about our approach to API pagination and how you can opt-in beforehand at %s.", + "Alias Contacts (CardDAV)": "Alias Contacts (CardDAV)", + "List contacts": "List contacts", + "Create contact": "Create contact", + "Retrieve contact": "Retrieve contact", + "Update contact": "Update contact", + "Delete contact": "Delete contact", + "Alias Calendars (CalDAV)": "Alias Calendars (CalDAV)", + "List calendars": "List calendars", + "Create calendar": "Create calendar", + "Retrieve calendar": "Retrieve calendar", + "Update calendar": "Update calendar", + "Delete calendar": "Delete calendar", + "Alias Messages (IMAP/POP3)": "Alias Messages (IMAP/POP3)", + "List and search for messages": "List and search for messages", + "Create message": "Create message", + "Retrieve message": "Retrieve message", + "Update message": "Update message", + "Delete message": "Delete message", + "Alias Folders (IMAP/POP3)": "Alias Folders (IMAP/POP3)", + "List folders": "List folders", + "Create folder": "Create folder", + "Retrieve folder": "Retrieve folder", + "Update folder": "Update folder", + "Delete folder": "Delete folder", + "Copy folder": "Copy folder", + "Outbound Emails": "Outbound Emails", + "Get outbound SMTP email limit": "Get outbound SMTP email limit", + "List outbound SMTP emails": "List outbound SMTP emails", + "Create outbound SMTP email": "Create outbound SMTP email", + "Retrieve outbound SMTP email": "Retrieve outbound SMTP email", + "Delete outbound SMTP email": "Delete outbound SMTP email", + "header (with the exception of": "header (with the exception of", + "Alias Contacts": "Alias Contacts", + "Alias Calendars": "Alias Calendars", + "Alias Mailboxes": "Alias Mailboxes", + "which use a": "which use a", + "generated alias username and password": "generated alias username and password", + "Don't worry – examples are provided below for you if you're not sure what this is.": "Don't worry – examples are provided below for you if you're not sure what this is.", + "As of November 1st, 2024 the API endpoints for": "As of November 1st, 2024 the API endpoints for", + "will default to": "will default to", + "max results per page. If you would like to opt-in to this behavior early, you can pass": "max results per page. If you would like to opt-in to this behavior early, you can pass", + "as an additional querystring parameter to the URL for the endpoint query.": "as an additional querystring parameter to the URL for the endpoint query.", + "Pagination is supported by all API endpoints that list results.": "Pagination is supported by all API endpoints that list results.", + "Simply provide the querystring properties": "Simply provide the querystring properties", + "(and optionally": "(and optionally", + "The property": "The property", + "should be a number greater than or equal to": "should be a number greater than or equal to", + ". If you provide": ". If you provide", + "(also a number), then the minimum value is": "(also a number), then the minimum value is", + "and maximum is": "and maximum is", + "(unless otherwise noted).": "(unless otherwise noted).", + "Page of results to return. If not specified, the": "Page of results to return. If not specified, the", + "value will be": "value will be", + ". Must be a number greater than or equal to": ". Must be a number greater than or equal to", + "Number of results to return per page. Defaults to": "Number of results to return per page. Defaults to", + "if not specified. Must be a number greater than or equal to": "if not specified. Must be a number greater than or equal to", + ", and less than or equal to": ", and less than or equal to", + "In order to determine whether or not more results are available, we provide these HTTP response headers (which you can parse in order to paginate programmatically):": "In order to determine whether or not more results are available, we provide these HTTP response headers (which you can parse in order to paginate programmatically):", + "HTTP Response Header": "HTTP Response Header", + "The total page count available.": "The total page count available.", + "The current page of results returned (e.g. based off": "The current page of results returned (e.g. based off", + "querystring parameter).": "querystring parameter).", + "The total number of results in the page returned (e.g. based off": "The total number of results in the page returned (e.g. based off", + "querystring parameter and actual results returned).": "querystring parameter and actual results returned).", + "The total number of items available across all pages.": "The total number of items available across all pages.", + "We provide a": "We provide a", + "HTTP response header you can parse as shown in the example. This is": "HTTP response header you can parse as shown in the example. This is", + "similar to GitHub": "similar to GitHub", + "(e.g. not all values will be provided if they are not relevant or available, e.g.": "(e.g. not all values will be provided if they are not relevant or available, e.g.", + "will not be provided if there is not another page).": "will not be provided if there is not another page).", + "Unlike other API endpoints, these require": "Unlike other API endpoints, these require", + "\"username\" equal to the alias username and \"password\" equal to the alias generated password as Basic Authorization headers.": "\"username\" equal to the alias username and \"password\" equal to the alias generated password as Basic Authorization headers.", + "This endpoint section is a work in progress and will be released (hopefully) in 2024. In the interim please use an IMAP client from the \"Apps\" dropdown in the navigation of our website.": "This endpoint section is a work in progress and will be released (hopefully) in 2024. In the interim please use an IMAP client from the \"Apps\" dropdown in the navigation of our website.", + "CardDAV support is not yet available, follow this discussion on GitHub for updates": "CardDAV support is not yet available, follow this discussion on GitHub for updates", + "Please ensure that you have followed setup instructions for your domain.": "Please ensure that you have followed setup instructions for your domain.", + "These instructions can be found in our FAQ section": "These instructions can be found in our FAQ section", + "Do you support receiving email with IMAP?": "Do you support receiving email with IMAP?", + "This will": "This will", + "send an email – it will only simply add the message to your mailbox folder (e.g. this is similar to the IMAP": "send an email – it will only simply add the message to your mailbox folder (e.g. this is similar to the IMAP", + "command). If you would like to send an email, then see": "command). If you would like to send an email, then see", + "below. After creating the outbound SMTP email, then you can append a copy of it using this endpoint to your alias' mailbox for storage purposes.": "below. After creating the outbound SMTP email, then you can append a copy of it using this endpoint to your alias' mailbox for storage purposes.", + "Folder endpoints with a folder's path": "Folder endpoints with a folder's path", + "as their endpoint are interchangeable with a folder's ID": "as their endpoint are interchangeable with a folder's ID", + ". This means you can refer to the folder by either its": ". This means you can refer to the folder by either its", + "These instructions can be found at": "These instructions can be found at", + "Note that this endpoint does not return property values for an email's": "Note that this endpoint does not return property values for an email's", + "Sort by a specific field (prefix with a single hyphen": "Sort by a specific field (prefix with a single hyphen", + "to sort in the reverse direction of that field). Defaults to": "to sort in the reverse direction of that field). Defaults to", + "if not set.": "if not set.", + "for more insight": "for more insight", + "as their endpoint are interchangeable with a domain's ID": "as their endpoint are interchangeable with a domain's ID", + "as an additional querystring parameter to the URL for the endpoint query. See": "as an additional querystring parameter to the URL for the endpoint query. See", + "(\"SRS\") address here to protect against spoofing with our SRS domain name. We also check the recipient against our": "(\"SRS\") address here to protect against spoofing with our SRS domain name. We also check the recipient against our", + "- this is only applicable for outbound SMTP and correlates to the email ID stored in My Account → Emails": "- this is only applicable for outbound SMTP and correlates to the email ID stored in My Account → Emails", + "Bank Transfer": "Bank Transfer", + "Domestic Wire Transfer (Enterprise)": "Domestic Wire Transfer (Enterprise)", + "International Wire Transfer (Enterprise)": "International Wire Transfer (Enterprise)" } \ No newline at end of file diff --git a/locales/es.json b/locales/es.json index 30d66d9fe..d40f8d6d4 100644 --- a/locales/es.json +++ b/locales/es.json @@ -10152,5 +10152,104 @@ "Reviews, comparison, screenshots and more for the 80 best email services.": "Reseñas, comparaciones, capturas de pantalla y más de los 80 mejores servicios de correo electrónico.", "The Missing Email": "El correo electrónico que falta", "14 Best Private Email Services in 2024": "Los 14 mejores servicios de correo electrónico privado en 2024", - "Reviews, comparison, screenshots and more for the 14 best private email services.": "Reseñas, comparaciones, capturas de pantalla y más de los 14 mejores servicios de correo electrónico privado." + "Reviews, comparison, screenshots and more for the 14 best private email services.": "Reseñas, comparaciones, capturas de pantalla y más de los 14 mejores servicios de correo electrónico privado.", + "Notice: API pagination required starting November 1st": "Aviso: paginación API requerida a partir del 1 de noviembre", + "Starting November 1st of this year we will be enforcing API pagination on our API endpoints for list domains and list domain aliases. Learn more about our approach to API pagination and how you can opt-in beforehand at %s.": "A partir del 1 de noviembre de este año, implementaremos la paginación de API en nuestros puntos finales de API para dominios de listas y alias de dominios de listas. Obtenga más información sobre nuestro enfoque de paginación de API y cómo puede optar por participar de antemano en %s .", + "Alias Contacts (CardDAV)": "Contactos de alias (CardDAV)", + "List contacts": "Lista de contactos", + "Create contact": "Crear contacto", + "Retrieve contact": "Recuperar contacto", + "Update contact": "Actualizar contacto", + "Delete contact": "Eliminar contacto", + "Alias Calendars (CalDAV)": "Calendarios de alias (CalDAV)", + "List calendars": "Lista de calendarios", + "Create calendar": "Crear calendario", + "Retrieve calendar": "Recuperar calendario", + "Update calendar": "Actualizar calendario", + "Delete calendar": "Eliminar calendario", + "Alias Messages (IMAP/POP3)": "Mensajes de alias (IMAP/POP3)", + "List and search for messages": "Listado y búsqueda de mensajes", + "Create message": "Crear mensaje", + "Retrieve message": "Recuperar mensaje", + "Update message": "Mensaje de actualización", + "Delete message": "Eliminar mensaje", + "Alias Folders (IMAP/POP3)": "Carpetas de alias (IMAP/POP3)", + "List folders": "Lista de carpetas", + "Create folder": "Crear carpeta", + "Retrieve folder": "Recuperar carpeta", + "Update folder": "Actualizar carpeta", + "Delete folder": "Eliminar carpeta", + "Copy folder": "Copiar carpeta", + "Outbound Emails": "Correos electrónicos salientes", + "Get outbound SMTP email limit": "Obtener el límite de correo electrónico SMTP saliente", + "List outbound SMTP emails": "Lista de correos electrónicos SMTP salientes", + "Create outbound SMTP email": "Crear correo electrónico SMTP saliente", + "Retrieve outbound SMTP email": "Recuperar correo electrónico SMTP saliente", + "Delete outbound SMTP email": "Eliminar correo electrónico SMTP saliente", + "header (with the exception of": "encabezado (con excepción de", + "Alias Contacts": "Contactos de alias", + "Alias Calendars": "Alias Calendarios", + "Alias Mailboxes": "Buzones de alias", + "which use a": "que utilizan un", + "generated alias username and password": "nombre de usuario y contraseña alias generados", + "Don't worry – examples are provided below for you if you're not sure what this is.": "No te preocupes, a continuación te proporcionamos ejemplos si no estás seguro de qué es esto.", + "As of November 1st, 2024 the API endpoints for": "A partir del 1 de noviembre de 2024, los puntos finales de API para", + "will default to": "El valor predeterminado será", + "max results per page. If you would like to opt-in to this behavior early, you can pass": "Máximo de resultados por página. Si desea optar por este comportamiento antes, puede pasar", + "as an additional querystring parameter to the URL for the endpoint query.": "como un parámetro de cadena de consulta adicional a la URL para la consulta del punto final.", + "Pagination is supported by all API endpoints that list results.": "La paginación es compatible con todos los puntos finales de API que enumeran resultados.", + "Simply provide the querystring properties": "Simplemente proporcione las propiedades de la cadena de consulta", + "(and optionally": "(y opcionalmente", + "The property": "La propiedad", + "should be a number greater than or equal to": "debe ser un número mayor o igual a", + ". If you provide": "Si usted proporciona", + "(also a number), then the minimum value is": "(también un número), entonces el valor mínimo es", + "and maximum is": "y el máximo es", + "(unless otherwise noted).": "(a menos que se indique lo contrario).", + "Page of results to return. If not specified, the": "Página de resultados a devolver. Si no se especifica, el", + "value will be": "El valor será", + ". Must be a number greater than or equal to": ". Debe ser un número mayor o igual a", + "Number of results to return per page. Defaults to": "Número de resultados que se devolverán por página. El valor predeterminado es", + "if not specified. Must be a number greater than or equal to": "Si no se especifica, debe ser un número mayor o igual a", + ", and less than or equal to": ", y menor o igual a", + "In order to determine whether or not more results are available, we provide these HTTP response headers (which you can parse in order to paginate programmatically):": "Para determinar si hay más resultados disponibles o no, proporcionamos estos encabezados de respuesta HTTP (que puede analizar para paginar programáticamente):", + "HTTP Response Header": "Encabezado de respuesta HTTP", + "The total page count available.": "El número total de páginas disponibles.", + "The current page of results returned (e.g. based off": "La página actual de resultados devueltos (por ejemplo, en función de", + "querystring parameter).": "parámetros de cadena de consulta).", + "The total number of results in the page returned (e.g. based off": "El número total de resultados devueltos en la página (por ejemplo, en función de", + "querystring parameter and actual results returned).": "parámetro de cadena de consulta y resultados reales devueltos).", + "The total number of items available across all pages.": "El número total de elementos disponibles en todas las páginas.", + "We provide a": "Ofrecemos una", + "HTTP response header you can parse as shown in the example. This is": "Encabezado de respuesta HTTP que puede analizar como se muestra en el ejemplo. Esto es", + "similar to GitHub": "similar a GitHub", + "(e.g. not all values will be provided if they are not relevant or available, e.g.": "(por ejemplo, no se proporcionarán todos los valores si no son relevantes o no están disponibles, por ejemplo", + "will not be provided if there is not another page).": "no se proporcionará si no hay otra página).", + "Unlike other API endpoints, these require": "A diferencia de otros puntos finales de API, estos requieren", + "\"username\" equal to the alias username and \"password\" equal to the alias generated password as Basic Authorization headers.": "\"nombre de usuario\" igual al nombre de usuario alias y \"contraseña\" igual a la contraseña generada por alias como encabezados de Autorización Básica.", + "This endpoint section is a work in progress and will be released (hopefully) in 2024. In the interim please use an IMAP client from the \"Apps\" dropdown in the navigation of our website.": "Esta sección de puntos finales es un trabajo en progreso y se lanzará (con suerte) en 2024. Mientras tanto, utilice un cliente IMAP del menú desplegable \"Aplicaciones\" en la navegación de nuestro sitio web.", + "CardDAV support is not yet available, follow this discussion on GitHub for updates": "La compatibilidad con CardDAV aún no está disponible. Siga esta discusión en GitHub para obtener actualizaciones.", + "Please ensure that you have followed setup instructions for your domain.": "Asegúrese de haber seguido las instrucciones de configuración para su dominio.", + "These instructions can be found in our FAQ section": "Estas instrucciones se pueden encontrar en nuestra sección de preguntas frecuentes", + "Do you support receiving email with IMAP?": "¿Es compatible la recepción de correo electrónico con IMAP?", + "This will": "Esto será", + "send an email – it will only simply add the message to your mailbox folder (e.g. this is similar to the IMAP": "enviar un correo electrónico: simplemente agregará el mensaje a su carpeta de buzón (por ejemplo, esto es similar a IMAP)", + "command). If you would like to send an email, then see": "comando). Si desea enviar un correo electrónico, consulte", + "below. After creating the outbound SMTP email, then you can append a copy of it using this endpoint to your alias' mailbox for storage purposes.": "A continuación. Después de crear el correo electrónico SMTP saliente, puede adjuntar una copia del mismo mediante este punto final al buzón de su alias para fines de almacenamiento.", + "Folder endpoints with a folder's path": "Puntos finales de carpeta con la ruta de una carpeta", + "as their endpoint are interchangeable with a folder's ID": "ya que sus puntos finales son intercambiables con el ID de una carpeta", + ". This means you can refer to the folder by either its": ". Esto significa que puede hacer referencia a la carpeta ya sea por su", + "These instructions can be found at": "Estas instrucciones se pueden encontrar en", + "Note that this endpoint does not return property values for an email's": "Tenga en cuenta que este punto final no devuelve valores de propiedad para un correo electrónico.", + "Sort by a specific field (prefix with a single hyphen": "Ordenar por un campo específico (prefijo con un solo guión)", + "to sort in the reverse direction of that field). Defaults to": "para ordenar en la dirección inversa de ese campo). El valor predeterminado es", + "if not set.": "Si no está configurado.", + "for more insight": "Para más información", + "as their endpoint are interchangeable with a domain's ID": "ya que sus puntos finales son intercambiables con el ID de un dominio", + "as an additional querystring parameter to the URL for the endpoint query. See": "como un parámetro de cadena de consulta adicional a la URL para la consulta del punto final. Ver", + "(\"SRS\") address here to protect against spoofing with our SRS domain name. We also check the recipient against our": "(\"SRS\") aquí para protegernos contra la suplantación de identidad con nuestro nombre de dominio SRS. También verificamos al destinatario con nuestra", + "- this is only applicable for outbound SMTP and correlates to the email ID stored in My Account → Emails": "- esto solo se aplica al SMTP saliente y se correlaciona con el ID de correo electrónico almacenado en Mi cuenta → Correos electrónicos", + "Bank Transfer": "Transferencia bancaria", + "Domestic Wire Transfer (Enterprise)": "Transferencia bancaria nacional (empresa)", + "International Wire Transfer (Enterprise)": "Transferencia bancaria internacional (empresa)" } \ No newline at end of file diff --git a/locales/fi.json b/locales/fi.json index 4723f3183..58e796030 100644 --- a/locales/fi.json +++ b/locales/fi.json @@ -10001,5 +10001,104 @@ "Reviews, comparison, screenshots and more for the 80 best email services.": "Arvostelut, vertailut, kuvakaappaukset ja paljon muuta 80 parhaasta sähköpostipalvelusta.", "The Missing Email": "Puuttuva sähköposti", "14 Best Private Email Services in 2024": "14 parasta yksityistä sähköpostipalvelua vuonna 2024", - "Reviews, comparison, screenshots and more for the 14 best private email services.": "Arvostelut, vertailut, kuvakaappaukset ja paljon muuta 14 parhaasta yksityisestä sähköpostipalvelusta." + "Reviews, comparison, screenshots and more for the 14 best private email services.": "Arvostelut, vertailut, kuvakaappaukset ja paljon muuta 14 parhaasta yksityisestä sähköpostipalvelusta.", + "Notice: API pagination required starting November 1st": "Huomautus: API-sivutus vaaditaan 1. marraskuuta alkaen", + "Starting November 1st of this year we will be enforcing API pagination on our API endpoints for list domains and list domain aliases. Learn more about our approach to API pagination and how you can opt-in beforehand at %s.": "Tämän vuoden 1. marraskuuta alkaen otamme käyttöön sovellusliittymän sivutuksen sovellusliittymäpäätepisteissämme luetteloverkkotunnuksille ja luettelon verkkotunnuksen aliaksille. Lue lisää lähestymistavastamme sovellusliittymän sivuttamiseen ja siitä, miten voit ottaa sen käyttöön etukäteen osoitteessa %s .", + "Alias Contacts (CardDAV)": "Alias-yhteystiedot (CardDAV)", + "List contacts": "Listaa yhteystiedot", + "Create contact": "Luo yhteystieto", + "Retrieve contact": "Hae yhteystieto", + "Update contact": "Päivitä yhteystieto", + "Delete contact": "Poista yhteystieto", + "Alias Calendars (CalDAV)": "Alias-kalenterit (CalDAV)", + "List calendars": "Listaa kalentereita", + "Create calendar": "Luo kalenteri", + "Retrieve calendar": "Hae kalenteri", + "Update calendar": "Päivitä kalenteri", + "Delete calendar": "Poista kalenteri", + "Alias Messages (IMAP/POP3)": "Aliasviestit (IMAP/POP3)", + "List and search for messages": "Listaa ja etsi viestejä", + "Create message": "Luo viesti", + "Retrieve message": "Hae viesti", + "Update message": "Päivitä viesti", + "Delete message": "Poista viesti", + "Alias Folders (IMAP/POP3)": "Aliaskansiot (IMAP/POP3)", + "List folders": "Listaa kansiot", + "Create folder": "Luo kansio", + "Retrieve folder": "Hae kansio", + "Update folder": "Päivitä kansio", + "Delete folder": "Poista kansio", + "Copy folder": "Kopioi kansio", + "Outbound Emails": "Lähtevät sähköpostit", + "Get outbound SMTP email limit": "Hae lähtevän SMTP-sähköpostin raja", + "List outbound SMTP emails": "Listaa lähtevät SMTP-sähköpostit", + "Create outbound SMTP email": "Luo lähtevä SMTP-sähköposti", + "Retrieve outbound SMTP email": "Hae lähtevä SMTP-sähköposti", + "Delete outbound SMTP email": "Poista lähtevä SMTP-sähköposti", + "header (with the exception of": "otsikko (paitsi", + "Alias Contacts": "Alias Yhteystiedot", + "Alias Calendars": "Alias kalenterit", + "Alias Mailboxes": "Alias Postilaatikot", + "which use a": "jotka käyttävät a", + "generated alias username and password": "luotu alias käyttäjätunnus ja salasana", + "Don't worry – examples are provided below for you if you're not sure what this is.": "Älä huoli – alla on esimerkkejä sinulle, jos et ole varma, mikä tämä on.", + "As of November 1st, 2024 the API endpoints for": "1. marraskuuta 2024 alkaen API-päätepisteet", + "will default to": "oletuksena", + "max results per page. If you would like to opt-in to this behavior early, you can pass": "max tulos per sivu. Jos haluat hyväksyä tämän toiminnan aikaisin, voit läpäistä", + "as an additional querystring parameter to the URL for the endpoint query.": "ylimääräisenä kyselymerkkijonoparametrina päätepistekyselyn URL-osoitteeseen.", + "Pagination is supported by all API endpoints that list results.": "Kaikki tulokset listaavat API-päätepisteet tukevat sivutusta.", + "Simply provide the querystring properties": "Anna vain kyselymerkkijonon ominaisuudet", + "(and optionally": "(ja valinnaisesti", + "The property": "Omaisuus", + "should be a number greater than or equal to": "tulee olla numero, joka on suurempi tai yhtä suuri kuin", + ". If you provide": ". Jos tarjoat", + "(also a number), then the minimum value is": "(myös numero), niin pienin arvo on", + "and maximum is": "ja maksimi on", + "(unless otherwise noted).": "(ellei toisin mainita).", + "Page of results to return. If not specified, the": "Palautettava tulossivu. Jos ei ole määritelty,", + "value will be": "arvo tulee olemaan", + ". Must be a number greater than or equal to": ". Numeron on oltava suurempi tai yhtä suuri kuin", + "Number of results to return per page. Defaults to": "Palautettavien tulosten määrä sivua kohden. Oletuksena", + "if not specified. Must be a number greater than or equal to": "jos ei ole määritelty. Numeron on oltava suurempi tai yhtä suuri kuin", + ", and less than or equal to": ", ja pienempi tai yhtä suuri kuin", + "In order to determine whether or not more results are available, we provide these HTTP response headers (which you can parse in order to paginate programmatically):": "Jotta voimme määrittää, onko lisää tuloksia saatavilla, tarjoamme nämä HTTP-vastausotsikot (jotka voit jäsentää ja sivuuttaa ohjelmallisesti):", + "HTTP Response Header": "HTTP-vastauksen otsikko", + "The total page count available.": "Saatavilla olevien sivujen kokonaismäärä.", + "The current page of results returned (e.g. based off": "Nykyinen tulossivu palasi (esim", + "querystring parameter).": "kyselymerkkijonoparametrit).", + "The total number of results in the page returned (e.g. based off": "Palautettujen tulosten kokonaismäärä sivulla (esim", + "querystring parameter and actual results returned).": "querystring-parametri ja palautetut todelliset tulokset).", + "The total number of items available across all pages.": "Kaikilla sivuilla käytettävissä olevien kohteiden kokonaismäärä.", + "We provide a": "Tarjoamme a", + "HTTP response header you can parse as shown in the example. This is": "HTTP-vastausotsikon voit jäsentää esimerkin mukaisesti. Tämä on", + "similar to GitHub": "samanlainen kuin GitHub", + "(e.g. not all values will be provided if they are not relevant or available, e.g.": "(esim. kaikkia arvoja ei anneta, jos ne eivät ole relevantteja tai saatavilla, esim.", + "will not be provided if there is not another page).": "ei toimiteta, jos toista sivua ei ole).", + "Unlike other API endpoints, these require": "Toisin kuin muut API-päätepisteet, nämä vaativat", + "\"username\" equal to the alias username and \"password\" equal to the alias generated password as Basic Authorization headers.": "\"username\" vastaa aliaksen käyttäjänimeä ja \"salasana\" vastaa aliaksen luomaa salasanaa Basic Authorization -otsikoina.", + "This endpoint section is a work in progress and will be released (hopefully) in 2024. In the interim please use an IMAP client from the \"Apps\" dropdown in the navigation of our website.": "Tämä päätepisteosio on työn alla, ja se julkaistaan (toivottavasti) vuonna 2024. Käytä sillä välin IMAP-asiakasta verkkosivustomme navigoinnin \"Sovellukset\"-pudotusvalikosta.", + "CardDAV support is not yet available, follow this discussion on GitHub for updates": "CardDAV-tuki ei ole vielä saatavilla. Seuraa tätä keskustelua GitHubissa päivityksiä varten", + "Please ensure that you have followed setup instructions for your domain.": "Varmista, että olet noudattanut verkkotunnuksesi asennusohjeita.", + "These instructions can be found in our FAQ section": "Nämä ohjeet löytyvät usein kysytyistä kysymyksistämme", + "Do you support receiving email with IMAP?": "Tuetko sähköpostin vastaanottamista IMAP-protokollalla?", + "This will": "Tämä tulee", + "send an email – it will only simply add the message to your mailbox folder (e.g. this is similar to the IMAP": "lähetä sähköposti – se vain lisää viestin postilaatikkosi kansioon (esim. tämä on samanlainen kuin IMAP", + "command). If you would like to send an email, then see": "komento). Jos haluat lähettää sähköpostia, katso", + "below. After creating the outbound SMTP email, then you can append a copy of it using this endpoint to your alias' mailbox for storage purposes.": "alla. Kun olet luonut lähtevän SMTP-sähköpostin, voit liittää sen kopion tämän päätepisteen avulla aliaksesi postilaatikkoon tallennustarkoituksiin.", + "Folder endpoints with a folder's path": "Kansion päätepisteet kansion polulla", + "as their endpoint are interchangeable with a folder's ID": "koska niiden päätepisteet ovat vaihdettavissa kansion tunnuksen kanssa", + ". This means you can refer to the folder by either its": ". Tämä tarkoittaa, että voit viitata kansioon kummalla tahansa sen perusteella", + "These instructions can be found at": "Nämä ohjeet löytyvät osoitteesta", + "Note that this endpoint does not return property values for an email's": "Huomaa, että tämä päätepiste ei palauta sähköpostin ominaisuusarvoja", + "Sort by a specific field (prefix with a single hyphen": "Lajittele tietyn kentän mukaan (etuliite yhdellä yhdysviivalla", + "to sort in the reverse direction of that field). Defaults to": "lajitella kentän vastakkaiseen suuntaan). Oletuksena", + "if not set.": "jos ei ole asetettu.", + "for more insight": "saadaksesi lisätietoa", + "as their endpoint are interchangeable with a domain's ID": "koska niiden päätepisteet ovat vaihdettavissa verkkotunnuksen tunnuksen kanssa", + "as an additional querystring parameter to the URL for the endpoint query. See": "ylimääräisenä kyselymerkkijonoparametrina päätepistekyselyn URL-osoitteeseen. Katso", + "(\"SRS\") address here to protect against spoofing with our SRS domain name. We also check the recipient against our": "(\"SRS\") -osoite suojataksesi SRS-verkkotunnuksemme huijauksilta. Tarkistamme myös vastaanottajan omaamme vastaan", + "- this is only applicable for outbound SMTP and correlates to the email ID stored in My Account → Emails": "- tämä koskee vain lähtevää SMTP:tä ja korreloi sähköpostitunnukseen, joka on tallennettu kohtaan Oma tili → Sähköpostit", + "Bank Transfer": "Pankkisiirto", + "Domestic Wire Transfer (Enterprise)": "Kotimainen pankkisiirto (yritys)", + "International Wire Transfer (Enterprise)": "Kansainvälinen pankkisiirto (yritys)" } \ No newline at end of file diff --git a/locales/fr.json b/locales/fr.json index 219563b8a..3953282b5 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -7676,5 +7676,105 @@ "Reviews, comparison, screenshots and more for the 80 best email services.": "Avis, comparaison, captures d'écran et plus pour les 80 meilleurs services de messagerie.", "The Missing Email": "L'e-mail manquant", "14 Best Private Email Services in 2024": "14 meilleurs services de messagerie privée en 2024", - "Reviews, comparison, screenshots and more for the 14 best private email services.": "Avis, comparaison, captures d'écran et plus pour les 14 meilleurs services de messagerie privée." + "Reviews, comparison, screenshots and more for the 14 best private email services.": "Avis, comparaison, captures d'écran et plus pour les 14 meilleurs services de messagerie privée.", + "Notice: API pagination required starting November 1st": "Attention : la pagination de l'API est obligatoire à partir du 1er novembre", + "Starting November 1st of this year we will be enforcing API pagination on our API endpoints for list domains and list domain aliases. Learn more about our approach to API pagination and how you can opt-in beforehand at %s.": "À partir du 1er novembre de cette année, nous appliquerons la pagination des API sur nos points de terminaison d'API pour les domaines de liste et les alias de domaine de liste. Pour en savoir plus sur notre approche de la pagination des API et sur la manière dont vous pouvez vous inscrire au préalable, rendez-vous sur %s .", + "Alias Contacts (CardDAV)": "Contacts d'alias (CardDAV)", + "List contacts": "Liste des contacts", + "Create contact": "Créer un contact", + "Retrieve contact": "Récupérer le contact", + "Update contact": "Mise à jour des contacts", + "Delete contact": "Supprimer le contact", + "Alias Calendars (CalDAV)": "Calendriers d'alias (CalDAV)", + "List calendars": "Liste des calendriers", + "Create calendar": "Créer un calendrier", + "Retrieve calendar": "Récupérer le calendrier", + "Update calendar": "Calendrier de mise à jour", + "Delete calendar": "Supprimer le calendrier", + "Alias Messages (IMAP/POP3)": "Messages d'alias (IMAP/POP3)", + "List and search for messages": "Lister et rechercher des messages", + "Create message": "Créer un message", + "Retrieve message": "Récupérer le message", + "Update message": "Message de mise à jour", + "Delete message": "Supprimer le message", + "Alias Folders (IMAP/POP3)": "Dossiers d'alias (IMAP/POP3)", + "List folders": "Liste des dossiers", + "Create folder": "Créer un dossier", + "Retrieve folder": "Récupérer le dossier", + "Update folder": "Mettre à jour le dossier", + "Delete folder": "Supprimer le dossier", + "Copy folder": "Copier le dossier", + "Outbound Emails": "Courriels sortants", + "Get outbound SMTP email limit": "Obtenir la limite des e-mails SMTP sortants", + "List outbound SMTP emails": "Lister les e-mails SMTP sortants", + "Create outbound SMTP email": "Créer un e-mail SMTP sortant", + "Retrieve outbound SMTP email": "Récupérer les e-mails SMTP sortants", + "Delete outbound SMTP email": "Supprimer les e-mails SMTP sortants", + "header (with the exception of": "en-tête (à l'exception de", + "Alias Contacts": "Contacts d'alias", + "Alias Calendars": "Calendriers d'alias", + "Alias Mailboxes": "Boîtes aux lettres d'alias", + "which use a": "qui utilisent un", + "generated alias username and password": "nom d'utilisateur et mot de passe d'alias générés", + "Don't worry – examples are provided below for you if you're not sure what this is.": "Ne vous inquiétez pas, des exemples sont fournis ci-dessous si vous n'êtes pas sûr de ce que c'est.", + "As of November 1st, 2024 the API endpoints for": "À compter du 1er novembre 2024, les points de terminaison de l'API pour", + "will default to": "sera par défaut", + "max results per page. If you would like to opt-in to this behavior early, you can pass": "max résultats par page. Si vous souhaitez accepter ce comportement plus tôt, vous pouvez passer", + "as an additional querystring parameter to the URL for the endpoint query.": "en tant que paramètre de chaîne de requête supplémentaire à l'URL pour la requête de point de terminaison.", + "Pagination is supported by all API endpoints that list results.": "La pagination est prise en charge par tous les points de terminaison d'API qui répertorient les résultats.", + "Simply provide the querystring properties": "Fournissez simplement les propriétés de la chaîne de requête", + "(and optionally": "(et éventuellement", + "The property": "La propriété", + "should be a number greater than or equal to": "doit être un nombre supérieur ou égal à", + ". If you provide": ". Si vous fournissez", + "(also a number), then the minimum value is": "(également un nombre), alors la valeur minimale est", + "and maximum is": "et le maximum est", + "(unless otherwise noted).": "(sauf indication contraire).", + "Page of results to return. If not specified, the": "Page de résultats à renvoyer. Si non spécifié, le", + "value will be": "la valeur sera", + ". Must be a number greater than or equal to": ". Doit être un nombre supérieur ou égal à", + "Number of results to return per page. Defaults to": "Nombre de résultats à renvoyer par page. La valeur par défaut est", + "if not specified. Must be a number greater than or equal to": "si non spécifié. Doit être un nombre supérieur ou égal à", + ", and less than or equal to": ", et inférieur ou égal à", + "In order to determine whether or not more results are available, we provide these HTTP response headers (which you can parse in order to paginate programmatically):": "Afin de déterminer si davantage de résultats sont disponibles ou non, nous fournissons ces en-têtes de réponse HTTP (que vous pouvez analyser afin de paginer par programmation) :", + "HTTP Response Header": "En-tête de réponse HTTP", + "The total page count available.": "Le nombre total de pages disponibles.", + "The current page of results returned (e.g. based off": "La page actuelle des résultats renvoyés (par exemple, en fonction de", + "querystring parameter).": "paramètres de chaîne de requête).", + "The total number of results in the page returned (e.g. based off": "Le nombre total de résultats renvoyés dans la page (par exemple, en fonction de", + "querystring parameter and actual results returned).": "paramètre de chaîne de requête et résultats réels renvoyés).", + "The total number of items available across all pages.": "Le nombre total d'éléments disponibles sur toutes les pages.", + "We provide a": "Nous fournissons un", + "HTTP response header you can parse as shown in the example. This is": "En-tête de réponse HTTP que vous pouvez analyser comme indiqué dans l'exemple. C'est", + "similar to GitHub": "similaire à GitHub", + "(e.g. not all values will be provided if they are not relevant or available, e.g.": "(par exemple, toutes les valeurs ne seront pas fournies si elles ne sont pas pertinentes ou disponibles, par exemple)", + "will not be provided if there is not another page).": "ne sera pas fourni s'il n'y a pas d'autre page).", + "Unlike other API endpoints, these require": "Contrairement à d’autres points de terminaison d’API, ceux-ci nécessitent", + "\"username\" equal to the alias username and \"password\" equal to the alias generated password as Basic Authorization headers.": "« nom d'utilisateur » égal au nom d'utilisateur de l'alias et « mot de passe » égal au mot de passe généré par l'alias comme en-têtes d'autorisation de base.", + "This endpoint section is a work in progress and will be released (hopefully) in 2024. In the interim please use an IMAP client from the \"Apps\" dropdown in the navigation of our website.": "Cette section de point de terminaison est un travail en cours et sera publiée (espérons-le) en 2024. En attendant, veuillez utiliser un client IMAP à partir du menu déroulant « Applications » dans la navigation de notre site Web.", + "CardDAV support is not yet available, follow this discussion on GitHub for updates": "Le support CardDAV n'est pas encore disponible, suivez cette discussion sur GitHub pour les mises à jour", + "Coming soon": "À venir", + "Please ensure that you have followed setup instructions for your domain.": "Veuillez vous assurer que vous avez suivi les instructions de configuration de votre domaine.", + "These instructions can be found in our FAQ section": "Ces instructions peuvent être trouvées dans notre section FAQ", + "Do you support receiving email with IMAP?": "Prenez-vous en charge la réception d'e-mails avec IMAP ?", + "This will": "Cela va", + "send an email – it will only simply add the message to your mailbox folder (e.g. this is similar to the IMAP": "envoyer un e-mail – cela ajoutera simplement le message à votre dossier de boîte aux lettres (par exemple, cela est similaire au protocole IMAP)", + "command). If you would like to send an email, then see": "commande). Si vous souhaitez envoyer un e-mail, consultez", + "below. After creating the outbound SMTP email, then you can append a copy of it using this endpoint to your alias' mailbox for storage purposes.": "ci-dessous. Après avoir créé l'e-mail SMTP sortant, vous pouvez en ajouter une copie à l'aide de ce point de terminaison dans la boîte aux lettres de votre alias à des fins de stockage.", + "Folder endpoints with a folder's path": "Points de terminaison de dossier avec le chemin d'un dossier", + "as their endpoint are interchangeable with a folder's ID": "car leur point de terminaison est interchangeable avec l'ID d'un dossier", + ". This means you can refer to the folder by either its": ". Cela signifie que vous pouvez faire référence au dossier soit par son", + "These instructions can be found at": "Ces instructions peuvent être trouvées à l'adresse", + "Note that this endpoint does not return property values for an email's": "Notez que ce point de terminaison ne renvoie pas de valeurs de propriété pour un e-mail.", + "Sort by a specific field (prefix with a single hyphen": "Trier par un champ spécifique (préfixe avec un seul tiret", + "to sort in the reverse direction of that field). Defaults to": "pour trier dans le sens inverse de ce champ). La valeur par défaut est", + "if not set.": "si non défini.", + "for more insight": "pour plus d'informations", + "as their endpoint are interchangeable with a domain's ID": "car leur point de terminaison est interchangeable avec l'ID d'un domaine", + "as an additional querystring parameter to the URL for the endpoint query. See": "en tant que paramètre de chaîne de requête supplémentaire à l'URL pour la requête du point de terminaison. Voir", + "(\"SRS\") address here to protect against spoofing with our SRS domain name. We also check the recipient against our": "(« SRS ») ici pour protéger contre l'usurpation d'identité avec notre nom de domaine SRS. Nous vérifions également le destinataire par rapport à notre", + "- this is only applicable for outbound SMTP and correlates to the email ID stored in My Account → Emails": "- ceci ne s'applique qu'au SMTP sortant et correspond à l'identifiant de messagerie stocké dans Mon compte → E-mails", + "Bank Transfer": "Virement bancaire", + "Domestic Wire Transfer (Enterprise)": "Virement bancaire national (entreprise)", + "International Wire Transfer (Enterprise)": "Virement bancaire international (entreprise)" } \ No newline at end of file diff --git a/locales/he.json b/locales/he.json index 752a95471..25d20b37a 100644 --- a/locales/he.json +++ b/locales/he.json @@ -8172,5 +8172,105 @@ "Reviews, comparison, screenshots and more for the 80 best email services.": "ביקורות, השוואה, צילומי מסך ועוד עבור 80 שירותי הדוא\"ל הטובים ביותר.", "The Missing Email": "האימייל החסר", "14 Best Private Email Services in 2024": "14 שירותי האימייל הפרטיים הטובים ביותר בשנת 2024", - "Reviews, comparison, screenshots and more for the 14 best private email services.": "ביקורות, השוואה, צילומי מסך ועוד עבור 14 שירותי האימייל הפרטיים הטובים ביותר." + "Reviews, comparison, screenshots and more for the 14 best private email services.": "ביקורות, השוואה, צילומי מסך ועוד עבור 14 שירותי האימייל הפרטיים הטובים ביותר.", + "Notice: API pagination required starting November 1st": "שים לב: נדרש עימוד של API החל מה-1 בנובמבר", + "Starting November 1st of this year we will be enforcing API pagination on our API endpoints for list domains and list domain aliases. Learn more about our approach to API pagination and how you can opt-in beforehand at %s.": "החל מה-1 בנובמבר השנה נאכוף עימוד API על נקודות הקצה של ה-API שלנו עבור דומיינים ברשימה וכינויים של דומיינים. למד עוד על הגישה שלנו לעימוד API וכיצד תוכל להצטרף מראש ב- %s .", + "Alias Contacts (CardDAV)": "אנשי קשר כינוי (CardDAV)", + "List contacts": "רשימת אנשי קשר", + "Create contact": "צור קשר", + "Retrieve contact": "אחזר איש קשר", + "Update contact": "עדכן איש קשר", + "Delete contact": "מחק איש קשר", + "Alias Calendars (CalDAV)": "יומני כינוי (CalDAV)", + "List calendars": "רשימת לוחות שנה", + "Create calendar": "צור לוח שנה", + "Retrieve calendar": "אחזר לוח שנה", + "Update calendar": "עדכן לוח שנה", + "Delete calendar": "מחק לוח שנה", + "Alias Messages (IMAP/POP3)": "הודעות כינוי (IMAP/POP3)", + "List and search for messages": "רשום וחפש הודעות", + "Create message": "צור הודעה", + "Retrieve message": "אחזר הודעה", + "Update message": "עדכון הודעה", + "Delete message": "מחק הודעה", + "Alias Folders (IMAP/POP3)": "תיקיות כינוי (IMAP/POP3)", + "List folders": "רשימת תיקיות", + "Create folder": "צור תיקייה", + "Retrieve folder": "אחזר תיקיה", + "Update folder": "עדכן תיקייה", + "Delete folder": "מחק תיקייה", + "Copy folder": "העתק תיקייה", + "Outbound Emails": "אימיילים יוצאים", + "Get outbound SMTP email limit": "קבל מגבלת דוא\"ל SMTP יוצא", + "List outbound SMTP emails": "רשום הודעות דוא\"ל SMTP יוצאות", + "Create outbound SMTP email": "צור דוא\"ל SMTP יוצא", + "Retrieve outbound SMTP email": "אחזר דוא\"ל SMTP יוצא", + "Delete outbound SMTP email": "מחק דוא\"ל SMTP יוצא", + "header (with the exception of": "כותרת עליונה (למעט", + "Alias Contacts": "כינוי אנשי קשר", + "Alias Calendars": "כינוי לוחות שנה", + "Alias Mailboxes": "כינוי תיבות דואר", + "which use a": "אשר משתמשים ב- a", + "generated alias username and password": "נוצר כינוי שם משתמש וסיסמה", + "Don't worry – examples are provided below for you if you're not sure what this is.": "אל תדאג - דוגמאות מסופקות להלן עבורך אם אינך בטוח מה זה.", + "As of November 1st, 2024 the API endpoints for": "החל מ-1 בנובמבר 2024, נקודות הקצה של ה-API עבור", + "will default to": "יהיה ברירת המחדל ל", + "max results per page. If you would like to opt-in to this behavior early, you can pass": "מקסימום תוצאות לכל עמוד. אם תרצה להצטרף להתנהגות זו מוקדם, תוכל לעבור", + "as an additional querystring parameter to the URL for the endpoint query.": "כפרמטר querystring נוסף לכתובת ה-URL עבור שאילתת נקודת הקצה.", + "Pagination is supported by all API endpoints that list results.": "העידון נתמך על ידי כל נקודות הקצה של API שמפרטות את התוצאות.", + "Simply provide the querystring properties": "כל שעליך לעשות הוא לספק את מאפייני מחרוזת השאילתה", + "(and optionally": "(ואופציונלי", + "The property": "הנכס", + "should be a number greater than or equal to": "צריך להיות מספר גדול או שווה ל", + ". If you provide": ". אם אתה מספק", + "(also a number), then the minimum value is": "(גם מספר), אז הערך המינימלי הוא", + "and maximum is": "ומקסימום הוא", + "(unless otherwise noted).": "(אלא אם צוין אחרת).", + "Page of results to return. If not specified, the": "דף תוצאות להחזרה. אם לא צוין, ה", + "value will be": "הערך יהיה", + ". Must be a number greater than or equal to": ". חייב להיות מספר גדול או שווה ל", + "Number of results to return per page. Defaults to": "מספר התוצאות להחזר בכל עמוד. ברירת מחדל ל", + "if not specified. Must be a number greater than or equal to": "אם לא צוין. חייב להיות מספר גדול או שווה ל", + ", and less than or equal to": ", ופחות או שווה ל", + "In order to determine whether or not more results are available, we provide these HTTP response headers (which you can parse in order to paginate programmatically):": "על מנת לקבוע אם תוצאות נוספות זמינות או לא, אנו מספקים את כותרות תגובת ה-HTTP הבאות (שאותן תוכל לנתח כדי לעימוד באופן פרוגרמטי):", + "HTTP Response Header": "כותרת תגובת HTTP", + "The total page count available.": "ספירת הדפים הכוללת הזמינה.", + "The current page of results returned (e.g. based off": "הדף הנוכחי של התוצאות שהוחזר (למשל, מבוסס כבוי", + "querystring parameter).": "פרמטרי querystring).", + "The total number of results in the page returned (e.g. based off": "המספר הכולל של התוצאות בדף שהוחזר (למשל, מבוסס על ביטול", + "querystring parameter and actual results returned).": "פרמטר querystring והתוצאות בפועל שהוחזרו).", + "The total number of items available across all pages.": "המספר הכולל של הפריטים הזמינים בכל הדפים.", + "We provide a": "אנו מספקים א", + "HTTP response header you can parse as shown in the example. This is": "כותרת תגובת HTTP תוכל לנתח כפי שמוצג בדוגמה. זֶהוּ", + "similar to GitHub": "דומה ל-GitHub", + "(e.g. not all values will be provided if they are not relevant or available, e.g.": "(לדוגמה, לא כל הערכים יסופקו אם הם לא רלוונטיים או זמינים, למשל.", + "will not be provided if there is not another page).": "לא יסופק אם אין דף נוסף).", + "Unlike other API endpoints, these require": "שלא כמו נקודות קצה אחרות של API, אלה דורשות", + "\"username\" equal to the alias username and \"password\" equal to the alias generated password as Basic Authorization headers.": "\"שם משתמש\" שווה לשם המשתמש הכינוי ו\"סיסמה\" שווה לסיסמה שנוצרה בכינוי ככותרות הרשאות בסיסיות.", + "This endpoint section is a work in progress and will be released (hopefully) in 2024. In the interim please use an IMAP client from the \"Apps\" dropdown in the navigation of our website.": "חלק זה של נקודות קצה הוא עבודה בתהליך והוא ישוחרר (בתקווה) בשנת 2024. בינתיים, אנא השתמש בלקוח IMAP מהתפריט הנפתח \"אפליקציות\" בניווט של האתר שלנו.", + "CardDAV support is not yet available, follow this discussion on GitHub for updates": "תמיכת CardDAV עדיין לא זמינה, עקוב אחר הדיון הזה ב-GitHub לקבלת עדכונים", + "Coming soon": "בקרוב", + "Please ensure that you have followed setup instructions for your domain.": "אנא ודא שעקבת אחר הוראות ההגדרה עבור הדומיין שלך.", + "These instructions can be found in our FAQ section": "ניתן למצוא הוראות אלו בחלק השאלות הנפוצות שלנו", + "Do you support receiving email with IMAP?": "האם אתה תומך בקבלת אימייל עם IMAP?", + "This will": "צוואה זו", + "send an email – it will only simply add the message to your mailbox folder (e.g. this is similar to the IMAP": "שלח אימייל - זה פשוט יוסיף את ההודעה לתיקיית תיבת הדואר שלך (למשל, זה דומה ל-IMAP", + "command). If you would like to send an email, then see": "פְּקוּדָה). אם תרצה לשלוח מייל, ראה", + "below. After creating the outbound SMTP email, then you can append a copy of it using this endpoint to your alias' mailbox for storage purposes.": "לְהַלָן. לאחר יצירת דוא\"ל ה-SMTP היוצא, תוכל לצרף עותק שלו באמצעות נקודת קצה זו לתיבת הדואר של הכינוי שלך למטרות אחסון.", + "Folder endpoints with a folder's path": "נקודות קצה של תיקיה עם נתיב של תיקיה", + "as their endpoint are interchangeable with a folder's ID": "מכיוון שנקודות הקצה שלהם ניתנות להחלפה עם מזהה תיקיה", + ". This means you can refer to the folder by either its": ". זה אומר שאתה יכול להתייחס לתיקיה לפי אחת מהן", + "These instructions can be found at": "ניתן למצוא הוראות אלו בכתובת", + "Note that this endpoint does not return property values for an email's": "שים לב שנקודת קצה זו אינה מחזירה ערכי מאפיינים עבור אימייל", + "Sort by a specific field (prefix with a single hyphen": "מיין לפי שדה ספציפי (קידומת עם מקף בודד", + "to sort in the reverse direction of that field). Defaults to": "כדי למיין בכיוון ההפוך של השדה הזה). ברירת מחדל ל", + "if not set.": "אם לא מוגדר.", + "for more insight": "לתובנה נוספת", + "as their endpoint are interchangeable with a domain's ID": "מכיוון שנקודות הקצה שלהם ניתנות להחלפה עם מזהה דומיין", + "as an additional querystring parameter to the URL for the endpoint query. See": "כפרמטר querystring נוסף לכתובת ה-URL עבור שאילתת נקודת הקצה. לִרְאוֹת", + "(\"SRS\") address here to protect against spoofing with our SRS domain name. We also check the recipient against our": "כתובת (\"SRS\") כאן כדי להגן מפני זיוף עם שם הדומיין SRS שלנו. אנחנו גם בודקים את הנמען מול שלנו", + "- this is only applicable for outbound SMTP and correlates to the email ID stored in My Account → Emails": "- זה ישים רק עבור SMTP יוצא ומתאם למזהה הדוא\"ל המאוחסן ב'חשבון שלי ← הודעות דוא\"ל", + "Bank Transfer": "העברה בנקאית", + "Domestic Wire Transfer (Enterprise)": "העברה בנקאית מקומית (ארגוני)", + "International Wire Transfer (Enterprise)": "העברה בנקאית בינלאומית (ארגוני)" } \ No newline at end of file diff --git a/locales/hu.json b/locales/hu.json index 2fedad69e..ca6dacaec 100644 --- a/locales/hu.json +++ b/locales/hu.json @@ -10154,5 +10154,104 @@ "Reviews, comparison, screenshots and more for the 80 best email services.": "Vélemények, összehasonlítások, képernyőképek és egyebek a 80 legjobb e-mail szolgáltatáshoz.", "The Missing Email": "A hiányzó e-mail", "14 Best Private Email Services in 2024": "A 14 legjobb privát e-mail szolgáltatás 2024", - "Reviews, comparison, screenshots and more for the 14 best private email services.": "Vélemények, összehasonlítás, képernyőképek és egyebek a 14 legjobb privát e-mail szolgáltatáshoz." + "Reviews, comparison, screenshots and more for the 14 best private email services.": "Vélemények, összehasonlítás, képernyőképek és egyebek a 14 legjobb privát e-mail szolgáltatáshoz.", + "Notice: API pagination required starting November 1st": "Megjegyzés: november 1-től API oldalszámozás szükséges", + "Starting November 1st of this year we will be enforcing API pagination on our API endpoints for list domains and list domain aliases. Learn more about our approach to API pagination and how you can opt-in beforehand at %s.": "Ez év november 1-jétől bevezetjük az API-oldalszámozást az API-végpontjainkon a listatartományokhoz és a listatartomány-aliasokhoz. Tudjon meg többet az API-oldalszámozással kapcsolatos megközelítésünkről és arról, hogyan regisztrálhat előzetesen: %s .", + "Alias Contacts (CardDAV)": "Alias Contacts (CardDAV)", + "List contacts": "Névjegyek listázása", + "Create contact": "Kapcsolat létrehozása", + "Retrieve contact": "Névjegy lekérése", + "Update contact": "Kapcsolattartó frissítése", + "Delete contact": "Névjegy törlése", + "Alias Calendars (CalDAV)": "Alias naptárak (CalDAV)", + "List calendars": "Naptárak listázása", + "Create calendar": "Naptár létrehozása", + "Retrieve calendar": "Naptár lekérése", + "Update calendar": "Naptár frissítése", + "Delete calendar": "Naptár törlése", + "Alias Messages (IMAP/POP3)": "Alias üzenetek (IMAP/POP3)", + "List and search for messages": "Üzenetek listázása és keresése", + "Create message": "Üzenet létrehozása", + "Retrieve message": "Üzenet lekérése", + "Update message": "Üzenet frissítése", + "Delete message": "Üzenet törlése", + "Alias Folders (IMAP/POP3)": "Alias mappák (IMAP/POP3)", + "List folders": "Mappák listázása", + "Create folder": "Mappa létrehozása", + "Retrieve folder": "Mappa lekérése", + "Update folder": "Mappa frissítése", + "Delete folder": "Mappa törlése", + "Copy folder": "Mappa másolása", + "Outbound Emails": "Kimenő e-mailek", + "Get outbound SMTP email limit": "Kimenő SMTP e-mailek korlátja", + "List outbound SMTP emails": "Kimenő SMTP e-mailek listázása", + "Create outbound SMTP email": "Hozzon létre kimenő SMTP e-mailt", + "Retrieve outbound SMTP email": "Kimenő SMTP e-mailek lekérése", + "Delete outbound SMTP email": "Kimenő SMTP e-mail törlése", + "header (with the exception of": "fejléc (kivéve", + "Alias Contacts": "Alias Kapcsolatok", + "Alias Calendars": "Alias naptárak", + "Alias Mailboxes": "Alias postafiókok", + "which use a": "amelyek a", + "generated alias username and password": "generált alias felhasználónév és jelszó", + "Don't worry – examples are provided below for you if you're not sure what this is.": "Ne aggódjon – az alábbiakban példákat mutatunk be, ha nem biztos benne, hogy mi ez.", + "As of November 1st, 2024 the API endpoints for": "2024. november 1-től az API-végpontok a következőhöz:", + "will default to": "alapértelmezett lesz", + "max results per page. If you would like to opt-in to this behavior early, you can pass": "oldalanként max. Ha korábban szeretne feliratkozni erre a viselkedésre, átadhatja", + "as an additional querystring parameter to the URL for the endpoint query.": "kiegészítő lekérdezési karakterlánc-paraméterként a végpont-lekérdezés URL-jéhez.", + "Pagination is supported by all API endpoints that list results.": "A lapozást az eredményeket listázó összes API-végpont támogatja.", + "Simply provide the querystring properties": "Egyszerűen adja meg a lekérdezési karakterlánc tulajdonságait", + "(and optionally": "(és opcionálisan", + "The property": "Az ingatlan", + "should be a number greater than or equal to": "nagyobbnak vagy egyenlőnek kell lennie, mint", + ". If you provide": ". Ha biztosítod", + "(also a number), then the minimum value is": "(szintén egy szám), akkor a minimális érték", + "and maximum is": "és maximum az", + "(unless otherwise noted).": "(hacsak nincs másképp jelezve).", + "Page of results to return. If not specified, the": "Visszaküldendő eredmények oldala. Ha nincs megadva, a", + "value will be": "értéke lesz", + ". Must be a number greater than or equal to": ". A számnak nagyobbnak vagy egyenlőnek kell lennie", + "Number of results to return per page. Defaults to": "Oldalanként visszaküldendő találatok száma. Alapértelmezés szerint", + "if not specified. Must be a number greater than or equal to": "ha nincs megadva. A számnak nagyobbnak vagy egyenlőnek kell lennie", + ", and less than or equal to": ", és kisebb vagy egyenlő, mint", + "In order to determine whether or not more results are available, we provide these HTTP response headers (which you can parse in order to paginate programmatically):": "Annak megállapítására, hogy elérhető-e több eredmény, a következő HTTP-válaszfejléceket biztosítjuk (amelyeket elemezhet a programozott oldalszámozáshoz):", + "HTTP Response Header": "HTTP válaszfejléc", + "The total page count available.": "A teljes elérhető oldalszám.", + "The current page of results returned (e.g. based off": "Az aktuális találati oldal visszaadott (pl", + "querystring parameter).": "lekérdezési karakterlánc paraméterei).", + "The total number of results in the page returned (e.g. based off": "Az oldalon visszaadott találatok teljes száma (pl", + "querystring parameter and actual results returned).": "querystring paraméter és a visszaadott tényleges eredmények).", + "The total number of items available across all pages.": "Az összes oldalon elérhető elemek teljes száma.", + "We provide a": "Biztosítjuk a", + "HTTP response header you can parse as shown in the example. This is": "A HTTP válaszfejlécet a példában látható módon elemezheti. Ez van", + "similar to GitHub": "hasonló a GitHubhoz", + "(e.g. not all values will be provided if they are not relevant or available, e.g.": "(pl. nem minden érték kerül megadásra, ha nem releváns vagy nem elérhető, pl.", + "will not be provided if there is not another page).": "nem adjuk meg, ha nincs másik oldal).", + "Unlike other API endpoints, these require": "Más API-végpontokkal ellentétben ezek megkövetelik", + "\"username\" equal to the alias username and \"password\" equal to the alias generated password as Basic Authorization headers.": "A \"felhasználónév\" megegyezik az alias felhasználónévvel és a \"password\" egyenlő az álnéven generált jelszóval Basic Authorization fejlécként.", + "This endpoint section is a work in progress and will be released (hopefully) in 2024. In the interim please use an IMAP client from the \"Apps\" dropdown in the navigation of our website.": "Ez a végpontszakasz folyamatban van, és (remélhetőleg) 2024-ben fog megjelenni. Addig is, kérjük, használjon IMAP-klienst a webhelyünk navigációs részének „Alkalmazások” legördülő menüjében.", + "CardDAV support is not yet available, follow this discussion on GitHub for updates": "A CardDAV-támogatás még nem érhető el. A frissítésekért kövesse ezt a vitát a GitHubon", + "Please ensure that you have followed setup instructions for your domain.": "Kérjük, győződjön meg arról, hogy követte a domain beállítási utasításait.", + "These instructions can be found in our FAQ section": "Ezeket az utasításokat a GYIK részben találja", + "Do you support receiving email with IMAP?": "Támogatja az e-mailek fogadását az IMAP használatával?", + "This will": "Ez lesz", + "send an email – it will only simply add the message to your mailbox folder (e.g. this is similar to the IMAP": "e-mail küldése – ez csak egyszerűen hozzáadja az üzenetet a postafiók mappájához (pl. ez hasonló az IMAP-hez", + "command). If you would like to send an email, then see": "parancs). Ha szeretne e-mailt küldeni, nézze meg", + "below. After creating the outbound SMTP email, then you can append a copy of it using this endpoint to your alias' mailbox for storage purposes.": "alatt. A kimenő SMTP e-mail létrehozása után tárolási célból hozzáfűzheti ennek a végpontnak a másolatát az alias postafiókjához.", + "Folder endpoints with a folder's path": "Mappavégpontok a mappa elérési útjával", + "as their endpoint are interchangeable with a folder's ID": "mivel a végpontjuk felcserélhető egy mappa azonosítójával", + ". This means you can refer to the folder by either its": ". Ez azt jelenti, hogy bármelyikével hivatkozhat a mappára", + "These instructions can be found at": "Ezek az utasítások a címen találhatók", + "Note that this endpoint does not return property values for an email's": "Vegye figyelembe, hogy ez a végpont nem ad vissza tulajdonságértékeket egy e-mailhez", + "Sort by a specific field (prefix with a single hyphen": "Rendezés adott mező szerint (előtag egyetlen kötőjellel", + "to sort in the reverse direction of that field). Defaults to": "az adott mező fordított irányába rendezni). Alapértelmezés szerint", + "if not set.": "ha nincs beállítva.", + "for more insight": "több betekintésért", + "as their endpoint are interchangeable with a domain's ID": "mivel a végpontjuk felcserélhető egy tartomány azonosítójával", + "as an additional querystring parameter to the URL for the endpoint query. See": "kiegészítő lekérdezési karakterlánc-paraméterként a végpont-lekérdezés URL-jéhez. Lásd", + "(\"SRS\") address here to protect against spoofing with our SRS domain name. We also check the recipient against our": "(\"SRS\") címe itt, hogy megvédje magát az SRS-domainnevünkkel való hamisítástól. Ellenőrizzük a címzettet is a miénkhez képest", + "- this is only applicable for outbound SMTP and correlates to the email ID stored in My Account → Emails": "- ez csak a kimenő SMTP-re vonatkozik, és a Saját fiók → E-mailek menüpontban tárolt e-mail azonosítóhoz kapcsolódik", + "Bank Transfer": "Banki átutalás", + "Domestic Wire Transfer (Enterprise)": "Belföldi banki átutalás (vállalati)", + "International Wire Transfer (Enterprise)": "Nemzetközi banki átutalás (vállalati)" } \ No newline at end of file diff --git a/locales/id.json b/locales/id.json index 5ccba78a5..994a1da0e 100644 --- a/locales/id.json +++ b/locales/id.json @@ -10154,5 +10154,104 @@ "Reviews, comparison, screenshots and more for the 80 best email services.": "Ulasan, perbandingan, tangkapan layar, dan banyak lagi untuk 80 layanan email terbaik.", "The Missing Email": "Email yang Hilang", "14 Best Private Email Services in 2024": "14 Layanan Email Pribadi Terbaik Tahun 2024", - "Reviews, comparison, screenshots and more for the 14 best private email services.": "Ulasan, perbandingan, tangkapan layar, dan lainnya untuk 14 layanan email pribadi terbaik." + "Reviews, comparison, screenshots and more for the 14 best private email services.": "Ulasan, perbandingan, tangkapan layar, dan lainnya untuk 14 layanan email pribadi terbaik.", + "Notice: API pagination required starting November 1st": "Pemberitahuan: Paginasi API diperlukan mulai 1 November", + "Starting November 1st of this year we will be enforcing API pagination on our API endpoints for list domains and list domain aliases. Learn more about our approach to API pagination and how you can opt-in beforehand at %s.": "Mulai tanggal 1 November tahun ini, kami akan memberlakukan penomoran halaman API pada titik akhir API kami untuk domain daftar dan alias domain daftar. Pelajari lebih lanjut tentang pendekatan kami terhadap penomoran halaman API dan bagaimana Anda dapat ikut serta sebelumnya di %s .", + "Alias Contacts (CardDAV)": "Kontak Alias (CardDAV)", + "List contacts": "Daftar kontak", + "Create contact": "Buat kontak", + "Retrieve contact": "Ambil kembali kontak", + "Update contact": "Perbarui kontak", + "Delete contact": "Hapus kontak", + "Alias Calendars (CalDAV)": "Kalender Alias (CalDAV)", + "List calendars": "Daftar kalender", + "Create calendar": "Buat kalender", + "Retrieve calendar": "Ambil kalender", + "Update calendar": "Perbarui kalender", + "Delete calendar": "Hapus kalender", + "Alias Messages (IMAP/POP3)": "Pesan Alias (IMAP/POP3)", + "List and search for messages": "Daftar dan cari pesan", + "Create message": "Buat pesan", + "Retrieve message": "Ambil pesan", + "Update message": "Perbarui pesan", + "Delete message": "Hapus pesan", + "Alias Folders (IMAP/POP3)": "Folder Alias (IMAP/POP3)", + "List folders": "Daftar folder", + "Create folder": "Buat folder", + "Retrieve folder": "Ambil kembali folder", + "Update folder": "Perbarui folder", + "Delete folder": "Hapus folder", + "Copy folder": "Salin folder", + "Outbound Emails": "Email Keluar", + "Get outbound SMTP email limit": "Dapatkan batas email SMTP keluar", + "List outbound SMTP emails": "Daftar email SMTP keluar", + "Create outbound SMTP email": "Buat email SMTP keluar", + "Retrieve outbound SMTP email": "Ambil email SMTP keluar", + "Delete outbound SMTP email": "Hapus email SMTP keluar", + "header (with the exception of": "header (kecuali", + "Alias Contacts": "Alias Kontak", + "Alias Calendars": "Kalender Alias", + "Alias Mailboxes": "Kotak Surat Alias", + "which use a": "yang menggunakan", + "generated alias username and password": "alias nama pengguna dan kata sandi yang dihasilkan", + "Don't worry – examples are provided below for you if you're not sure what this is.": "Jangan khawatir – contoh disediakan di bawah ini untuk Anda jika Anda tidak yakin apa ini.", + "As of November 1st, 2024 the API endpoints for": "Mulai 1 November 2024, titik akhir API untuk", + "will default to": "akan default ke", + "max results per page. If you would like to opt-in to this behavior early, you can pass": "hasil maksimal per halaman. Jika Anda ingin ikut serta dalam perilaku ini lebih awal, Anda dapat meneruskannya", + "as an additional querystring parameter to the URL for the endpoint query.": "sebagai parameter querystring tambahan ke URL untuk kueri titik akhir.", + "Pagination is supported by all API endpoints that list results.": "Paginasi didukung oleh semua titik akhir API yang mencantumkan hasil.", + "Simply provide the querystring properties": "Cukup berikan properti querystring", + "(and optionally": "(dan opsional", + "The property": "Properti", + "should be a number greater than or equal to": "harus berupa angka yang lebih besar atau sama dengan", + ". If you provide": "Jika Anda memberikan", + "(also a number), then the minimum value is": "(juga angka), maka nilai minimumnya adalah", + "and maximum is": "dan maksimum adalah", + "(unless otherwise noted).": "(kecuali dinyatakan lain).", + "Page of results to return. If not specified, the": "Halaman hasil yang akan dikembalikan. Jika tidak ditentukan,", + "value will be": "nilai akan menjadi", + ". Must be a number greater than or equal to": ". Harus berupa angka yang lebih besar atau sama dengan", + "Number of results to return per page. Defaults to": "Jumlah hasil yang akan dikembalikan per halaman. Defaultnya adalah", + "if not specified. Must be a number greater than or equal to": "jika tidak ditentukan. Harus berupa angka yang lebih besar atau sama dengan", + ", and less than or equal to": ", dan kurang dari atau sama dengan", + "In order to determine whether or not more results are available, we provide these HTTP response headers (which you can parse in order to paginate programmatically):": "Untuk menentukan apakah ada hasil tambahan yang tersedia atau tidak, kami berikan header respons HTTP ini (yang dapat Anda uraikan untuk melakukan paginasi secara terprogram):", + "HTTP Response Header": "Header Respons HTTP", + "The total page count available.": "Jumlah total halaman yang tersedia.", + "The current page of results returned (e.g. based off": "Halaman hasil saat ini yang dikembalikan (misalnya berdasarkan", + "querystring parameter).": "parameter string kueri).", + "The total number of results in the page returned (e.g. based off": "Jumlah total hasil yang dikembalikan di halaman (misalnya berdasarkan", + "querystring parameter and actual results returned).": "parameter querystring dan hasil aktual yang dikembalikan).", + "The total number of items available across all pages.": "Jumlah total item yang tersedia di semua halaman.", + "We provide a": "Kami menyediakan", + "HTTP response header you can parse as shown in the example. This is": "Header respons HTTP dapat Anda parse seperti yang ditunjukkan pada contoh. Ini adalah", + "similar to GitHub": "mirip dengan GitHub", + "(e.g. not all values will be provided if they are not relevant or available, e.g.": "(misalnya tidak semua nilai akan diberikan jika tidak relevan atau tersedia, misalnya", + "will not be provided if there is not another page).": "tidak akan disediakan jika tidak ada halaman lain).", + "Unlike other API endpoints, these require": "Tidak seperti titik akhir API lainnya, ini memerlukan", + "\"username\" equal to the alias username and \"password\" equal to the alias generated password as Basic Authorization headers.": "\"nama pengguna\" sama dengan alias nama pengguna dan \"kata sandi\" sama dengan alias kata sandi yang dihasilkan sebagai header Otorisasi Dasar.", + "This endpoint section is a work in progress and will be released (hopefully) in 2024. In the interim please use an IMAP client from the \"Apps\" dropdown in the navigation of our website.": "Bagian titik akhir ini masih dalam tahap pengerjaan dan akan dirilis (semoga) pada tahun 2024. Untuk sementara, harap gunakan klien IMAP dari menu tarik-turun \"Aplikasi\" di navigasi situs web kami.", + "CardDAV support is not yet available, follow this discussion on GitHub for updates": "Dukungan CardDAV belum tersedia, ikuti diskusi ini di GitHub untuk pembaruan", + "Please ensure that you have followed setup instructions for your domain.": "Pastikan Anda telah mengikuti petunjuk pengaturan untuk domain Anda.", + "These instructions can be found in our FAQ section": "Instruksi ini dapat ditemukan di bagian FAQ kami", + "Do you support receiving email with IMAP?": "Apakah Anda mendukung penerimaan email dengan IMAP?", + "This will": "Ini akan", + "send an email – it will only simply add the message to your mailbox folder (e.g. this is similar to the IMAP": "kirim email – ini hanya akan menambahkan pesan ke folder kotak surat Anda (misalnya ini mirip dengan IMAP", + "command). If you would like to send an email, then see": "perintah). Jika Anda ingin mengirim email, maka lihat", + "below. After creating the outbound SMTP email, then you can append a copy of it using this endpoint to your alias' mailbox for storage purposes.": "di bawah. Setelah membuat email SMTP keluar, Anda dapat menambahkan salinannya menggunakan titik akhir ini ke kotak surat alias Anda untuk tujuan penyimpanan.", + "Folder endpoints with a folder's path": "Titik akhir folder dengan jalur folder", + "as their endpoint are interchangeable with a folder's ID": "karena titik akhirnya dapat dipertukarkan dengan ID folder", + ". This means you can refer to the folder by either its": "Ini berarti Anda dapat merujuk ke folder dengan salah satu", + "These instructions can be found at": "Petunjuk ini dapat ditemukan di", + "Note that this endpoint does not return property values for an email's": "Perhatikan bahwa titik akhir ini tidak mengembalikan nilai properti untuk email", + "Sort by a specific field (prefix with a single hyphen": "Urutkan berdasarkan bidang tertentu (diawali dengan tanda hubung tunggal)", + "to sort in the reverse direction of that field). Defaults to": "untuk mengurutkan dalam arah yang berlawanan dengan bidang tersebut). Defaultnya adalah", + "if not set.": "jika tidak disetel.", + "for more insight": "untuk wawasan lebih dalam", + "as their endpoint are interchangeable with a domain's ID": "karena titik akhirnya dapat dipertukarkan dengan ID domain", + "as an additional querystring parameter to the URL for the endpoint query. See": "sebagai parameter querystring tambahan ke URL untuk kueri titik akhir. Lihat", + "(\"SRS\") address here to protect against spoofing with our SRS domain name. We also check the recipient against our": "(\"SRS\") di sini untuk melindungi dari spoofing dengan nama domain SRS kami. Kami juga memeriksa penerima terhadap", + "- this is only applicable for outbound SMTP and correlates to the email ID stored in My Account → Emails": "- ini hanya berlaku untuk SMTP keluar dan berkorelasi dengan ID email yang disimpan di Akun Saya → Email", + "Bank Transfer": "Transfer Bank", + "Domestic Wire Transfer (Enterprise)": "Transfer Kawat Domestik (Perusahaan)", + "International Wire Transfer (Enterprise)": "Transfer Bank Internasional (Perusahaan)" } \ No newline at end of file diff --git a/locales/it.json b/locales/it.json index cbf625a50..5dd52a250 100644 --- a/locales/it.json +++ b/locales/it.json @@ -10154,5 +10154,104 @@ "Reviews, comparison, screenshots and more for the 80 best email services.": "Recensioni, confronti, screenshot e altro ancora sui 80 migliori servizi di posta elettronica.", "The Missing Email": "L'email mancante", "14 Best Private Email Services in 2024": "14 migliori servizi di posta elettronica privati nel 2024", - "Reviews, comparison, screenshots and more for the 14 best private email services.": "Recensioni, confronti, screenshot e altro sui 14 migliori servizi di posta elettronica privati." + "Reviews, comparison, screenshots and more for the 14 best private email services.": "Recensioni, confronti, screenshot e altro sui 14 migliori servizi di posta elettronica privati.", + "Notice: API pagination required starting November 1st": "Avviso: la paginazione API è obbligatoria a partire dal 1° novembre", + "Starting November 1st of this year we will be enforcing API pagination on our API endpoints for list domains and list domain aliases. Learn more about our approach to API pagination and how you can opt-in beforehand at %s.": "A partire dal 1° novembre di quest'anno applicheremo la paginazione API sui nostri endpoint API per domini di elenco e alias di dominio di elenco. Scopri di più sul nostro approccio alla paginazione API e su come puoi aderire in anticipo su %s .", + "Alias Contacts (CardDAV)": "Contatti alias (CardDAV)", + "List contacts": "Elenca i contatti", + "Create contact": "Crea contatto", + "Retrieve contact": "Recupera contatto", + "Update contact": "Aggiorna contatto", + "Delete contact": "Elimina contatto", + "Alias Calendars (CalDAV)": "Calendari alias (CalDAV)", + "List calendars": "Elenca i calendari", + "Create calendar": "Crea calendario", + "Retrieve calendar": "Recupera calendario", + "Update calendar": "Aggiorna il calendario", + "Delete calendar": "Elimina calendario", + "Alias Messages (IMAP/POP3)": "Messaggi alias (IMAP/POP3)", + "List and search for messages": "Elenca e cerca i messaggi", + "Create message": "Crea messaggio", + "Retrieve message": "Recupera messaggio", + "Update message": "Aggiorna messaggio", + "Delete message": "Elimina messaggio", + "Alias Folders (IMAP/POP3)": "Cartelle alias (IMAP/POP3)", + "List folders": "Elenca le cartelle", + "Create folder": "Crea cartella", + "Retrieve folder": "Recupera cartella", + "Update folder": "Aggiorna cartella", + "Delete folder": "Elimina cartella", + "Copy folder": "Copia cartella", + "Outbound Emails": "Email in uscita", + "Get outbound SMTP email limit": "Ottieni il limite di posta elettronica SMTP in uscita", + "List outbound SMTP emails": "Elenca le email SMTP in uscita", + "Create outbound SMTP email": "Crea email SMTP in uscita", + "Retrieve outbound SMTP email": "Recupera email SMTP in uscita", + "Delete outbound SMTP email": "Elimina email SMTP in uscita", + "header (with the exception of": "intestazione (ad eccezione di", + "Alias Contacts": "Contatti Alias", + "Alias Calendars": "Calendari Alias", + "Alias Mailboxes": "Caselle postali alias", + "which use a": "che utilizzano un", + "generated alias username and password": "alias generato nome utente e password", + "Don't worry – examples are provided below for you if you're not sure what this is.": "Non preoccuparti: di seguito sono riportati degli esempi se non sei sicuro di cosa si tratta.", + "As of November 1st, 2024 the API endpoints for": "A partire dal 1° novembre 2024 gli endpoint API per", + "will default to": "sarà impostato di default su", + "max results per page. If you would like to opt-in to this behavior early, you can pass": "risultati massimi per pagina. Se desideri aderire a questo comportamento in anticipo, puoi passare", + "as an additional querystring parameter to the URL for the endpoint query.": "come parametro querystring aggiuntivo all'URL per la query dell'endpoint.", + "Pagination is supported by all API endpoints that list results.": "La paginazione è supportata da tutti gli endpoint API che elencano i risultati.", + "Simply provide the querystring properties": "Fornire semplicemente le proprietà della querystring", + "(and optionally": "(e facoltativamente", + "The property": "La proprietà", + "should be a number greater than or equal to": "dovrebbe essere un numero maggiore o uguale a", + ". If you provide": "Se fornisci", + "(also a number), then the minimum value is": "(anche un numero), allora il valore minimo è", + "and maximum is": "e il massimo è", + "(unless otherwise noted).": "(salvo diversa indicazione).", + "Page of results to return. If not specified, the": "Pagina dei risultati da restituire. Se non specificato, il", + "value will be": "il valore sarà", + ". Must be a number greater than or equal to": "Deve essere un numero maggiore o uguale a", + "Number of results to return per page. Defaults to": "Numero di risultati da restituire per pagina. Il valore predefinito è", + "if not specified. Must be a number greater than or equal to": "se non specificato. Deve essere un numero maggiore o uguale a", + ", and less than or equal to": ", e minore o uguale a", + "In order to determine whether or not more results are available, we provide these HTTP response headers (which you can parse in order to paginate programmatically):": "Per determinare se sono disponibili altri risultati, forniamo queste intestazioni di risposta HTTP (che puoi analizzare per la suddivisione in pagine a livello di programmazione):", + "HTTP Response Header": "Intestazione di risposta HTTP", + "The total page count available.": "Numero totale di pagine disponibili.", + "The current page of results returned (e.g. based off": "La pagina corrente dei risultati restituiti (ad esempio in base a", + "querystring parameter).": "parametri della stringa di query).", + "The total number of results in the page returned (e.g. based off": "Il numero totale di risultati nella pagina restituiti (ad esempio in base a", + "querystring parameter and actual results returned).": "parametro querystring e risultati effettivi restituiti).", + "The total number of items available across all pages.": "Numero totale di articoli disponibili in tutte le pagine.", + "We provide a": "Forniamo un", + "HTTP response header you can parse as shown in the example. This is": "Intestazione di risposta HTTP che puoi analizzare come mostrato nell'esempio. Questo è", + "similar to GitHub": "simile a GitHub", + "(e.g. not all values will be provided if they are not relevant or available, e.g.": "(ad esempio, non tutti i valori verranno forniti se non sono pertinenti o disponibili, ad esempio", + "will not be provided if there is not another page).": "non verrà fornito se non è presente un'altra pagina).", + "Unlike other API endpoints, these require": "A differenza di altri endpoint API, questi richiedono", + "\"username\" equal to the alias username and \"password\" equal to the alias generated password as Basic Authorization headers.": "\"username\" uguale all'alias username e \"password\" uguale alla password generata dall'alias come intestazioni di autorizzazione di base.", + "This endpoint section is a work in progress and will be released (hopefully) in 2024. In the interim please use an IMAP client from the \"Apps\" dropdown in the navigation of our website.": "Questa sezione endpoint è un work in progress e verrà rilasciata (si spera) nel 2024. Nel frattempo, si prega di utilizzare un client IMAP dal menu a discesa \"App\" nella navigazione del nostro sito Web.", + "CardDAV support is not yet available, follow this discussion on GitHub for updates": "Il supporto CardDAV non è ancora disponibile, segui questa discussione su GitHub per gli aggiornamenti", + "Please ensure that you have followed setup instructions for your domain.": "Assicurati di aver seguito le istruzioni di configurazione per il tuo dominio.", + "These instructions can be found in our FAQ section": "Queste istruzioni possono essere trovate nella nostra sezione FAQ", + "Do you support receiving email with IMAP?": "Supportate la ricezione di email con IMAP?", + "This will": "Questo lo farà", + "send an email – it will only simply add the message to your mailbox folder (e.g. this is similar to the IMAP": "invia un'e-mail: aggiungerà semplicemente il messaggio alla cartella della tua casella di posta (ad esempio, questo è simile all'IMAP", + "command). If you would like to send an email, then see": "comando). Se vuoi inviare un'e-mail, allora vedi", + "below. After creating the outbound SMTP email, then you can append a copy of it using this endpoint to your alias' mailbox for storage purposes.": "di seguito. Dopo aver creato l'e-mail SMTP in uscita, puoi aggiungerne una copia utilizzando questo endpoint alla casella di posta del tuo alias per scopi di archiviazione.", + "Folder endpoints with a folder's path": "Endpoint della cartella con il percorso di una cartella", + "as their endpoint are interchangeable with a folder's ID": "poiché il loro endpoint è intercambiabile con l'ID di una cartella", + ". This means you can refer to the folder by either its": "Ciò significa che puoi fare riferimento alla cartella tramite il suo", + "These instructions can be found at": "Queste istruzioni possono essere trovate su", + "Note that this endpoint does not return property values for an email's": "Si noti che questo endpoint non restituisce valori di proprietà per un'e-mail", + "Sort by a specific field (prefix with a single hyphen": "Ordina per un campo specifico (prefisso con un singolo trattino)", + "to sort in the reverse direction of that field). Defaults to": "per ordinare nella direzione inversa di quel campo). Il valore predefinito è", + "if not set.": "se non impostato.", + "for more insight": "per maggiori informazioni", + "as their endpoint are interchangeable with a domain's ID": "poiché il loro endpoint è intercambiabile con l'ID di un dominio", + "as an additional querystring parameter to the URL for the endpoint query. See": "come parametro querystring aggiuntivo all'URL per la query dell'endpoint. Vedere", + "(\"SRS\") address here to protect against spoofing with our SRS domain name. We also check the recipient against our": "(\"SRS\") qui per proteggerci dallo spoofing con il nostro nome di dominio SRS. Controlliamo anche il destinatario rispetto al nostro", + "- this is only applicable for outbound SMTP and correlates to the email ID stored in My Account → Emails": "- questo è applicabile solo per SMTP in uscita e si correla all'ID e-mail memorizzato in Il mio account → E-mail", + "Bank Transfer": "Bonifico bancario", + "Domestic Wire Transfer (Enterprise)": "Bonifico bancario nazionale (impresa)", + "International Wire Transfer (Enterprise)": "Bonifico bancario internazionale (aziendale)" } \ No newline at end of file diff --git a/locales/ja.json b/locales/ja.json index db61e6818..46736930b 100644 --- a/locales/ja.json +++ b/locales/ja.json @@ -10154,5 +10154,104 @@ "Reviews, comparison, screenshots and more for the 80 best email services.": "ベスト 80 のメール サービスのレビュー、比較、スクリーンショットなど。", "The Missing Email": "消えたメール", "14 Best Private Email Services in 2024": "2024のベスト プライベート メール サービス 14 選", - "Reviews, comparison, screenshots and more for the 14 best private email services.": "ベスト 14 のプライベート メール サービスのレビュー、比較、スクリーンショットなど。" + "Reviews, comparison, screenshots and more for the 14 best private email services.": "ベスト 14 のプライベート メール サービスのレビュー、比較、スクリーンショットなど。", + "Notice: API pagination required starting November 1st": "お知らせ: 11月1日からAPIページネーションが必要となります", + "Starting November 1st of this year we will be enforcing API pagination on our API endpoints for list domains and list domain aliases. Learn more about our approach to API pagination and how you can opt-in beforehand at %s.": "今年 11 月 1 日より、リスト ドメインとリスト ドメイン エイリアスの API エンドポイントで API ページネーションを実施します。API ページネーションへのアプローチと、事前にオプトインする方法の詳細については、%sをご覧ください。", + "Alias Contacts (CardDAV)": "エイリアス連絡先 (CardDAV)", + "List contacts": "連絡先を一覧表示する", + "Create contact": "連絡先を作成", + "Retrieve contact": "連絡先を取得", + "Update contact": "連絡先を更新", + "Delete contact": "連絡先を削除", + "Alias Calendars (CalDAV)": "エイリアスカレンダー (CalDAV)", + "List calendars": "カレンダーを一覧表示する", + "Create calendar": "カレンダーを作成", + "Retrieve calendar": "カレンダーを取得", + "Update calendar": "カレンダーを更新", + "Delete calendar": "カレンダーを削除", + "Alias Messages (IMAP/POP3)": "エイリアスメッセージ (IMAP/POP3)", + "List and search for messages": "メッセージの一覧と検索", + "Create message": "メッセージを作成", + "Retrieve message": "メッセージを取得", + "Update message": "メッセージを更新", + "Delete message": "メッセージを削除", + "Alias Folders (IMAP/POP3)": "エイリアス フォルダ (IMAP/POP3)", + "List folders": "フォルダの一覧", + "Create folder": "フォルダを作成", + "Retrieve folder": "フォルダを取得", + "Update folder": "フォルダを更新", + "Delete folder": "フォルダを削除", + "Copy folder": "フォルダをコピー", + "Outbound Emails": "送信メール", + "Get outbound SMTP email limit": "送信SMTPメールの制限を取得する", + "List outbound SMTP emails": "送信SMTPメールを一覧表示する", + "Create outbound SMTP email": "送信SMTPメールを作成する", + "Retrieve outbound SMTP email": "送信SMTPメールを取得する", + "Delete outbound SMTP email": "送信SMTPメールを削除する", + "header (with the exception of": "ヘッダー(", + "Alias Contacts": "エイリアス連絡先", + "Alias Calendars": "エイリアスカレンダー", + "Alias Mailboxes": "エイリアスメールボックス", + "which use a": "使用する", + "generated alias username and password": "生成されたエイリアスのユーザー名とパスワード", + "Don't worry – examples are provided below for you if you're not sure what this is.": "心配しないでください。これが何なのかわからない場合は、以下に例を示します。", + "As of November 1st, 2024 the API endpoints for": "2024年11月1日現在、APIエンドポイントは", + "will default to": "デフォルトは", + "max results per page. If you would like to opt-in to this behavior early, you can pass": "1ページあたり最大結果数。この動作を早期にオプトインしたい場合は、", + "as an additional querystring parameter to the URL for the endpoint query.": "エンドポイント クエリの URL への追加のクエリ文字列パラメータとして。", + "Pagination is supported by all API endpoints that list results.": "ページネーションは、結果をリストするすべての API エンドポイントでサポートされています。", + "Simply provide the querystring properties": "クエリ文字列のプロパティを指定するだけです", + "(and optionally": "(オプションで", + "The property": "物件", + "should be a number greater than or equal to": "以上の数値である必要があります", + ". If you provide": ". 提供する場合", + "(also a number), then the minimum value is": "(これも数値)の場合、最小値は", + "and maximum is": "そして最大値は", + "(unless otherwise noted).": "(特に記載のない限り)。", + "Page of results to return. If not specified, the": "返される結果のページ。指定しない場合は、", + "value will be": "価値は", + ". Must be a number greater than or equal to": "以上の数値でなければなりません", + "Number of results to return per page. Defaults to": "ページごとに返される結果の数。デフォルトは", + "if not specified. Must be a number greater than or equal to": "指定されていない場合は、", + ", and less than or equal to": "、以下", + "In order to determine whether or not more results are available, we provide these HTTP response headers (which you can parse in order to paginate programmatically):": "さらに結果が利用可能かどうかを判断するために、次の HTTP 応答ヘッダーを提供します (これを解析してプログラムでページ分割できます)。", + "HTTP Response Header": "HTTP レスポンス ヘッダー", + "The total page count available.": "利用可能なページの総数。", + "The current page of results returned (e.g. based off": "返された結果の現在のページ(例:", + "querystring parameter).": "クエリ文字列パラメータ)。", + "The total number of results in the page returned (e.g. based off": "返されたページ内の結果の合計数(例:", + "querystring parameter and actual results returned).": "クエリ文字列パラメータと実際に返される結果)。", + "The total number of items available across all pages.": "すべてのページで利用可能なアイテムの合計数。", + "We provide a": "私たちは、", + "HTTP response header you can parse as shown in the example. This is": "HTTPレスポンスヘッダーは例のように解析できます。これは", + "similar to GitHub": "GitHubに似ている", + "(e.g. not all values will be provided if they are not relevant or available, e.g.": "(例: 関連性がなかったり利用できない場合は、すべての値が提供されるわけではありません。", + "will not be provided if there is not another page).": "別のページがない場合は提供されません。", + "Unlike other API endpoints, these require": "他のAPIエンドポイントとは異なり、これらには", + "\"username\" equal to the alias username and \"password\" equal to the alias generated password as Basic Authorization headers.": "「username」はエイリアスのユーザー名に等しく、「password」は基本認証ヘッダーとしてエイリアスで生成されたパスワードに等しくなります。", + "This endpoint section is a work in progress and will be released (hopefully) in 2024. In the interim please use an IMAP client from the \"Apps\" dropdown in the navigation of our website.": "このエンドポイント セクションは現在開発中であり、(うまくいけば) 2024 年にリリースされる予定です。それまでの間、当社の Web サイトのナビゲーションにある [アプリ] ドロップダウンから IMAP クライアントを使用してください。", + "CardDAV support is not yet available, follow this discussion on GitHub for updates": "CardDAVのサポートはまだ利用できません。最新情報についてはGitHubのこのディスカッションを参照してください。", + "Please ensure that you have followed setup instructions for your domain.": "ドメインのセットアップ手順に従っていることを確認してください。", + "These instructions can be found in our FAQ section": "これらの手順はFAQセクションに記載されています。", + "Do you support receiving email with IMAP?": "IMAP によるメールの受信をサポートしていますか?", + "This will": "これにより", + "send an email – it will only simply add the message to your mailbox folder (e.g. this is similar to the IMAP": "メールを送信する – 単にメッセージをメールボックスフォルダに追加するだけです(これはIMAPに似ています)。", + "command). If you would like to send an email, then see": "コマンドを使用します。メールを送信したい場合は、", + "below. After creating the outbound SMTP email, then you can append a copy of it using this endpoint to your alias' mailbox for storage purposes.": "以下を参照してください。送信 SMTP メールを作成したら、このエンドポイントを使用してそのコピーをエイリアスのメールボックスに追加し、保存することができます。", + "Folder endpoints with a folder's path": "フォルダのパスを持つフォルダエンドポイント", + "as their endpoint are interchangeable with a folder's ID": "エンドポイントはフォルダのIDと交換可能である", + ". This means you can refer to the folder by either its": "つまり、フォルダを", + "These instructions can be found at": "これらの手順については、", + "Note that this endpoint does not return property values for an email's": "このエンドポイントはメールのプロパティ値を返さないことに注意してください。", + "Sort by a specific field (prefix with a single hyphen": "特定のフィールドで並べ替える(先頭にハイフン1つ)", + "to sort in the reverse direction of that field). Defaults to": "(そのフィールドの逆方向に並べ替える)デフォルトは", + "if not set.": "設定されていない場合は。", + "for more insight": "より詳しい情報", + "as their endpoint are interchangeable with a domain's ID": "エンドポイントはドメインのIDと交換可能であるため", + "as an additional querystring parameter to the URL for the endpoint query. See": "エンドポイントクエリのURLに追加のクエリ文字列パラメータとして指定します。", + "(\"SRS\") address here to protect against spoofing with our SRS domain name. We also check the recipient against our": "(「SRS」)アドレスをここに入力して、SRSドメイン名によるなりすましから保護します。また、受信者を当社の", + "- this is only applicable for outbound SMTP and correlates to the email ID stored in My Account → Emails": "- これは送信SMTPにのみ適用され、マイアカウント→メールに保存されているメールIDと相関します。", + "Bank Transfer": "銀行振込", + "Domestic Wire Transfer (Enterprise)": "国内電信送金(企業)", + "International Wire Transfer (Enterprise)": "国際電信送金(エンタープライズ)" } \ No newline at end of file diff --git a/locales/ko.json b/locales/ko.json index 010795697..36ae2a358 100644 --- a/locales/ko.json +++ b/locales/ko.json @@ -10154,5 +10154,104 @@ "Reviews, comparison, screenshots and more for the 80 best email services.": "80개의 최고 이메일 서비스에 대한 리뷰, 비교, 스크린샷 등.", "The Missing Email": "누락된 이메일", "14 Best Private Email Services in 2024": "2024 최고의 개인 이메일 서비스 14가지", - "Reviews, comparison, screenshots and more for the 14 best private email services.": "최고의 개인 이메일 서비스 14개에 대한 리뷰, 비교, 스크린샷 등." + "Reviews, comparison, screenshots and more for the 14 best private email services.": "최고의 개인 이메일 서비스 14개에 대한 리뷰, 비교, 스크린샷 등.", + "Notice: API pagination required starting November 1st": "공지: 11월 1일부터 API 페이지 매김이 필요합니다.", + "Starting November 1st of this year we will be enforcing API pagination on our API endpoints for list domains and list domain aliases. Learn more about our approach to API pagination and how you can opt-in beforehand at %s.": "올해 11월 1일부터 목록 도메인 및 목록 도메인 별칭에 대한 API 엔드포인트에서 API 페이지 매김을 시행합니다. %s 에서 API 페이지 매김에 대한 접근 방식과 사전에 옵트인하는 방법에 대해 자세히 알아보세요.", + "Alias Contacts (CardDAV)": "별칭 연락처(CardDAV)", + "List contacts": "연락처 목록", + "Create contact": "연락처 만들기", + "Retrieve contact": "연락처 검색", + "Update contact": "연락처 업데이트", + "Delete contact": "연락처 삭제", + "Alias Calendars (CalDAV)": "별칭 달력(CalDAV)", + "List calendars": "달력 목록", + "Create calendar": "캘린더 만들기", + "Retrieve calendar": "달력 검색", + "Update calendar": "캘린더 업데이트", + "Delete calendar": "캘린더 삭제", + "Alias Messages (IMAP/POP3)": "별칭 메시지(IMAP/POP3)", + "List and search for messages": "메시지 목록 및 검색", + "Create message": "메시지 작성", + "Retrieve message": "메시지 검색", + "Update message": "메시지 업데이트", + "Delete message": "메시지 삭제", + "Alias Folders (IMAP/POP3)": "별칭 폴더(IMAP/POP3)", + "List folders": "폴더 목록", + "Create folder": "폴더 생성", + "Retrieve folder": "폴더 검색", + "Update folder": "폴더 업데이트", + "Delete folder": "폴더 삭제", + "Copy folder": "폴더 복사", + "Outbound Emails": "아웃바운드 이메일", + "Get outbound SMTP email limit": "아웃바운드 SMTP 이메일 제한 받기", + "List outbound SMTP emails": "아웃바운드 SMTP 이메일 나열", + "Create outbound SMTP email": "아웃바운드 SMTP 이메일 생성", + "Retrieve outbound SMTP email": "아웃바운드 SMTP 이메일 검색", + "Delete outbound SMTP email": "아웃바운드 SMTP 이메일 삭제", + "header (with the exception of": "헤더(예외 포함)", + "Alias Contacts": "별칭 연락처", + "Alias Calendars": "별칭 달력", + "Alias Mailboxes": "별칭 사서함", + "which use a": "를 사용하는", + "generated alias username and password": "생성된 별칭 사용자 이름 및 비밀번호", + "Don't worry – examples are provided below for you if you're not sure what this is.": "걱정하지 마세요. 이것이 무엇인지 확실하지 않다면 아래에 예를 들어 설명하겠습니다.", + "As of November 1st, 2024 the API endpoints for": "2024년 11월 1일부터 API 엔드포인트는 다음과 같습니다.", + "will default to": "기본값으로 설정됩니다", + "max results per page. If you would like to opt-in to this behavior early, you can pass": "페이지당 최대 결과. 이 동작에 일찍 참여하려면 다음을 통과할 수 있습니다.", + "as an additional querystring parameter to the URL for the endpoint query.": "엔드포인트 쿼리에 대한 URL에 추가 쿼리문자열 매개변수로 사용합니다.", + "Pagination is supported by all API endpoints that list results.": "페이지 매김은 결과를 나열하는 모든 API 엔드포인트에서 지원됩니다.", + "Simply provide the querystring properties": "쿼리 문자열 속성을 제공하기만 하면 됩니다.", + "(and optionally": "(그리고 선택적으로", + "The property": "부동산", + "should be a number greater than or equal to": "숫자보다 크거나 같아야 합니다.", + ". If you provide": ". 당신이 제공하는 경우", + "(also a number), then the minimum value is": "(숫자도 있음) 그러면 최소값은 다음과 같습니다.", + "and maximum is": "그리고 최대값은", + "(unless otherwise noted).": "(다른 언급이 없는 한).", + "Page of results to return. If not specified, the": "반환할 결과 페이지입니다. 지정하지 않으면", + "value will be": "가치가 될 것이다", + ". Must be a number greater than or equal to": ". 숫자보다 크거나 같아야 합니다.", + "Number of results to return per page. Defaults to": "페이지당 반환할 결과 수. 기본값은 다음과 같습니다.", + "if not specified. Must be a number greater than or equal to": "지정되지 않은 경우. 다음보다 크거나 같은 숫자여야 합니다.", + ", and less than or equal to": ", 및 이하", + "In order to determine whether or not more results are available, we provide these HTTP response headers (which you can parse in order to paginate programmatically):": "더 많은 결과가 있는지 확인하기 위해 다음과 같은 HTTP 응답 헤더를 제공합니다(프로그래밍 방식으로 페이지를 나누기 위해 구문 분석 가능):", + "HTTP Response Header": "HTTP 응답 헤더", + "The total page count available.": "사용 가능한 총 페이지 수입니다.", + "The current page of results returned (e.g. based off": "반환된 결과의 현재 페이지(예:", + "querystring parameter).": "쿼리 문자열 매개변수).", + "The total number of results in the page returned (e.g. based off": "반환된 페이지의 총 결과 수(예:", + "querystring parameter and actual results returned).": "쿼리 문자열 매개변수와 실제 반환된 결과).", + "The total number of items available across all pages.": "모든 페이지에서 사용할 수 있는 항목의 총 수입니다.", + "We provide a": "우리는 제공합니다", + "HTTP response header you can parse as shown in the example. This is": "예시에 표시된 대로 분석할 수 있는 HTTP 응답 헤더입니다. 이것은", + "similar to GitHub": "GitHub와 유사", + "(e.g. not all values will be provided if they are not relevant or available, e.g.": "(예: 관련이 없거나 사용할 수 없는 경우 모든 값이 제공되지는 않습니다. 예:", + "will not be provided if there is not another page).": "(다른 페이지가 없는 경우에는 제공되지 않습니다).", + "Unlike other API endpoints, these require": "다른 API 엔드포인트와 달리 여기에는 다음이 필요합니다.", + "\"username\" equal to the alias username and \"password\" equal to the alias generated password as Basic Authorization headers.": "\"사용자 이름\"은 별칭 사용자 이름과 동일하고 \"비밀번호\"는 기본 인증 헤더로 생성된 별칭 비밀번호와 동일합니다.", + "This endpoint section is a work in progress and will be released (hopefully) in 2024. In the interim please use an IMAP client from the \"Apps\" dropdown in the navigation of our website.": "이 엔드포인트 섹션은 진행 중인 작업이며 (희망적으로) 2024년에 출시될 예정입니다. 그동안은 웹사이트 탐색의 \"앱\" 드롭다운에서 IMAP 클라이언트를 사용하세요.", + "CardDAV support is not yet available, follow this discussion on GitHub for updates": "CardDAV 지원은 아직 제공되지 않습니다. 업데이트 사항은 GitHub에서 이 토론을 참조하세요.", + "Please ensure that you have followed setup instructions for your domain.": "귀하의 도메인에 대한 설정 지침을 꼭 따르세요.", + "These instructions can be found in our FAQ section": "이러한 지침은 FAQ 섹션에서 찾을 수 있습니다.", + "Do you support receiving email with IMAP?": "IMAP를 사용하여 이메일을 수신하는 것을 지원하시나요?", + "This will": "이것은", + "send an email – it will only simply add the message to your mailbox folder (e.g. this is similar to the IMAP": "이메일을 보내세요. 메시지를 사서함 폴더에 추가하는 것만 가능합니다(예: IMAP와 유사합니다.", + "command). If you would like to send an email, then see": "명령). 이메일을 보내려면 다음을 참조하세요.", + "below. After creating the outbound SMTP email, then you can append a copy of it using this endpoint to your alias' mailbox for storage purposes.": "아래. 아웃바운드 SMTP 이메일을 만든 후, 이 엔드포인트를 사용하여 별칭의 사서함에 복사본을 추가하여 저장할 수 있습니다.", + "Folder endpoints with a folder's path": "폴더 경로를 포함한 폴더 엔드포인트", + "as their endpoint are interchangeable with a folder's ID": "그들의 엔드포인트는 폴더의 ID와 호환 가능합니다.", + ". This means you can refer to the folder by either its": ". 즉, 폴더를 다음 중 하나로 참조할 수 있습니다.", + "These instructions can be found at": "이 지침은 다음에서 찾을 수 있습니다.", + "Note that this endpoint does not return property values for an email's": "이 엔드포인트는 이메일의 속성 값을 반환하지 않습니다.", + "Sort by a specific field (prefix with a single hyphen": "특정 필드로 정렬(단일 하이픈이 있는 접두사)", + "to sort in the reverse direction of that field). Defaults to": "해당 필드의 역방향으로 정렬합니다. 기본값은 다음과 같습니다.", + "if not set.": "설정되지 않은 경우.", + "for more insight": "더 많은 통찰력을 위해", + "as their endpoint are interchangeable with a domain's ID": "그들의 엔드포인트는 도메인 ID와 상호 교환 가능합니다.", + "as an additional querystring parameter to the URL for the endpoint query. See": "엔드포인트 쿼리의 URL에 대한 추가 쿼리 문자열 매개변수로. 참조", + "(\"SRS\") address here to protect against spoofing with our SRS domain name. We also check the recipient against our": "(\"SRS\") 여기에 SRS 도메인 이름을 사용하여 스푸핑으로부터 보호합니다. 또한 수신자를 당사와 비교하여 확인합니다.", + "- this is only applicable for outbound SMTP and correlates to the email ID stored in My Account → Emails": "- 이것은 아웃바운드 SMTP에만 적용되며 내 계정 → 이메일에 저장된 이메일 ID와 상관 관계가 있습니다.", + "Bank Transfer": "은행 송금", + "Domestic Wire Transfer (Enterprise)": "국내 송금(기업)", + "International Wire Transfer (Enterprise)": "국제 송금(기업)" } \ No newline at end of file diff --git a/locales/nl.json b/locales/nl.json index 39a5fcdb1..66af8b88e 100644 --- a/locales/nl.json +++ b/locales/nl.json @@ -10154,5 +10154,104 @@ "Reviews, comparison, screenshots and more for the 80 best email services.": "Beoordelingen, vergelijkingen, screenshots en meer van de 80 beste e-mailservices.", "The Missing Email": "De ontbrekende e-mail", "14 Best Private Email Services in 2024": "14 beste privé-e-mailservices in 2024", - "Reviews, comparison, screenshots and more for the 14 best private email services.": "Beoordelingen, vergelijkingen, screenshots en meer van de 14 beste privé-e-mailservices." + "Reviews, comparison, screenshots and more for the 14 best private email services.": "Beoordelingen, vergelijkingen, screenshots en meer van de 14 beste privé-e-mailservices.", + "Notice: API pagination required starting November 1st": "Let op: API-paginering vereist vanaf 1 november", + "Starting November 1st of this year we will be enforcing API pagination on our API endpoints for list domains and list domain aliases. Learn more about our approach to API pagination and how you can opt-in beforehand at %s.": "Vanaf 1 november van dit jaar zullen we API-paginering afdwingen op onze API-eindpunten voor lijstdomeinen en lijstdomeinaliassen. Lees meer over onze aanpak van API-paginering en hoe u zich vooraf kunt aanmelden op %s .", + "Alias Contacts (CardDAV)": "Alias-contacten (CardDAV)", + "List contacts": "Contactenlijst", + "Create contact": "Contactpersoon aanmaken", + "Retrieve contact": "Contactpersoon ophalen", + "Update contact": "Contactpersoon bijwerken", + "Delete contact": "Contactpersoon verwijderen", + "Alias Calendars (CalDAV)": "Alias-kalenders (CalDAV)", + "List calendars": "Lijst kalenders", + "Create calendar": "Kalender maken", + "Retrieve calendar": "Kalender ophalen", + "Update calendar": "Kalender bijwerken", + "Delete calendar": "Kalender verwijderen", + "Alias Messages (IMAP/POP3)": "Aliasberichten (IMAP/POP3)", + "List and search for messages": "Berichten weergeven en zoeken", + "Create message": "Bericht maken", + "Retrieve message": "Bericht ophalen", + "Update message": "Bericht bijwerken", + "Delete message": "Bericht verwijderen", + "Alias Folders (IMAP/POP3)": "Alias-mappen (IMAP/POP3)", + "List folders": "Mappen weergeven", + "Create folder": "Map maken", + "Retrieve folder": "Map ophalen", + "Update folder": "Map bijwerken", + "Delete folder": "Map verwijderen", + "Copy folder": "Kopieer map", + "Outbound Emails": "Uitgaande e-mails", + "Get outbound SMTP email limit": "Uitgaande SMTP-e-maillimiet ophalen", + "List outbound SMTP emails": "Lijst met uitgaande SMTP-e-mails", + "Create outbound SMTP email": "Uitgaande SMTP-e-mail maken", + "Retrieve outbound SMTP email": "Uitgaande SMTP-e-mail ophalen", + "Delete outbound SMTP email": "Uitgaande SMTP-e-mail verwijderen", + "header (with the exception of": "header (met uitzondering van", + "Alias Contacts": "Alias-contacten", + "Alias Calendars": "Alias Kalenders", + "Alias Mailboxes": "Alias-mailboxen", + "which use a": "die gebruik maken van een", + "generated alias username and password": "gegenereerde alias gebruikersnaam en wachtwoord", + "Don't worry – examples are provided below for you if you're not sure what this is.": "Maakt u zich geen zorgen: hieronder vindt u voorbeelden als u niet zeker weet wat dit is.", + "As of November 1st, 2024 the API endpoints for": "Vanaf 1 november 2024 zijn de API-eindpunten voor", + "will default to": "zal standaard naar", + "max results per page. If you would like to opt-in to this behavior early, you can pass": "max. resultaten per pagina. Als u zich vroegtijdig voor dit gedrag wilt aanmelden, kunt u", + "as an additional querystring parameter to the URL for the endpoint query.": "als een extra querystringparameter voor de URL voor de eindpuntquery.", + "Pagination is supported by all API endpoints that list results.": "Paginering wordt ondersteund door alle API-eindpunten die resultaten weergeven.", + "Simply provide the querystring properties": "Geef eenvoudig de querystring-eigenschappen op", + "(and optionally": "(en optioneel", + "The property": "Het pand", + "should be a number greater than or equal to": "moet een getal zijn dat groter is dan of gelijk is aan", + ". If you provide": ". Als u verstrekt", + "(also a number), then the minimum value is": "(ook een getal), dan is de minimumwaarde", + "and maximum is": "en maximaal is", + "(unless otherwise noted).": "(tenzij anders vermeld).", + "Page of results to return. If not specified, the": "Pagina met resultaten om terug te keren. Indien niet gespecificeerd, de", + "value will be": "waarde zal zijn", + ". Must be a number greater than or equal to": ". Moet een getal zijn dat groter is dan of gelijk is aan", + "Number of results to return per page. Defaults to": "Aantal resultaten dat per pagina wordt geretourneerd. Standaardwaarde is", + "if not specified. Must be a number greater than or equal to": "indien niet gespecificeerd. Moet een getal zijn dat groter is dan of gelijk is aan", + ", and less than or equal to": ", en kleiner dan of gelijk aan", + "In order to determine whether or not more results are available, we provide these HTTP response headers (which you can parse in order to paginate programmatically):": "Om te bepalen of er meer resultaten beschikbaar zijn, bieden we de volgende HTTP-responsheaders aan (die u kunt parseren om programmatisch te pagineren):", + "HTTP Response Header": "HTTP-reactieheader", + "The total page count available.": "Het totale beschikbare aantal pagina's.", + "The current page of results returned (e.g. based off": "De huidige pagina met geretourneerde resultaten (bijvoorbeeld op basis van", + "querystring parameter).": "querytekenreeksparameters).", + "The total number of results in the page returned (e.g. based off": "Het totale aantal resultaten dat op de pagina is geretourneerd (bijv. op basis van", + "querystring parameter and actual results returned).": "querystringparameter en de daadwerkelijke geretourneerde resultaten).", + "The total number of items available across all pages.": "Het totale aantal items dat beschikbaar is op alle pagina's.", + "We provide a": "Wij bieden een", + "HTTP response header you can parse as shown in the example. This is": "HTTP-responsheader die u kunt parseren zoals getoond in het voorbeeld. Dit is", + "similar to GitHub": "vergelijkbaar met GitHub", + "(e.g. not all values will be provided if they are not relevant or available, e.g.": "(bijvoorbeeld worden niet alle waarden verstrekt als ze niet relevant of beschikbaar zijn, bijvoorbeeld", + "will not be provided if there is not another page).": "wordt niet verstrekt als er geen andere pagina is).", + "Unlike other API endpoints, these require": "In tegenstelling tot andere API-eindpunten vereisen deze", + "\"username\" equal to the alias username and \"password\" equal to the alias generated password as Basic Authorization headers.": "\"gebruikersnaam\" is gelijk aan de aliasgebruikersnaam en \"wachtwoord\" is gelijk aan het door de alias gegenereerde wachtwoord als basisautorisatieheaders.", + "This endpoint section is a work in progress and will be released (hopefully) in 2024. In the interim please use an IMAP client from the \"Apps\" dropdown in the navigation of our website.": "Deze eindpuntsectie is nog in ontwikkeling en wordt (hopelijk) in 2024 uitgebracht. Gebruik in de tussentijd een IMAP-client uit de vervolgkeuzelijst 'Apps' in de navigatie van onze website.", + "CardDAV support is not yet available, follow this discussion on GitHub for updates": "CardDAV-ondersteuning is nog niet beschikbaar, volg deze discussie op GitHub voor updates", + "Please ensure that you have followed setup instructions for your domain.": "Zorg ervoor dat u de installatie-instructies voor uw domein hebt gevolgd.", + "These instructions can be found in our FAQ section": "Deze instructies vindt u in onze FAQ-sectie", + "Do you support receiving email with IMAP?": "Ondersteunt u het ontvangen van e-mail via IMAP?", + "This will": "Dit zal", + "send an email – it will only simply add the message to your mailbox folder (e.g. this is similar to the IMAP": "een e-mail verzenden – het bericht wordt dan alleen maar aan uw mailboxmap toegevoegd (dit is bijvoorbeeld vergelijkbaar met de IMAP-methode).", + "command). If you would like to send an email, then see": "commando). Als u een e-mail wilt sturen, zie dan", + "below. After creating the outbound SMTP email, then you can append a copy of it using this endpoint to your alias' mailbox for storage purposes.": "hieronder. Nadat u de uitgaande SMTP-e-mail hebt gemaakt, kunt u een kopie ervan met behulp van dit eindpunt toevoegen aan de mailbox van uw alias voor opslagdoeleinden.", + "Folder endpoints with a folder's path": "Map-eindpunten met het pad van een map", + "as their endpoint are interchangeable with a folder's ID": "omdat hun eindpunten uitwisselbaar zijn met de ID van een map", + ". This means you can refer to the folder by either its": "Dit betekent dat u naar de map kunt verwijzen via de naam", + "These instructions can be found at": "Deze instructies vindt u op", + "Note that this endpoint does not return property values for an email's": "Houd er rekening mee dat dit eindpunt geen eigenschapswaarden retourneert voor de e-mail van een gebruiker.", + "Sort by a specific field (prefix with a single hyphen": "Sorteren op een specifiek veld (voorvoegsel met een enkel streepje)", + "to sort in the reverse direction of that field). Defaults to": "om in de omgekeerde richting van dat veld te sorteren). Standaard is", + "if not set.": "indien niet ingesteld.", + "for more insight": "voor meer inzicht", + "as their endpoint are interchangeable with a domain's ID": "omdat hun eindpunten uitwisselbaar zijn met de ID van een domein", + "as an additional querystring parameter to the URL for the endpoint query. See": "als een extra querystringparameter voor de URL voor de eindpuntquery. Zie", + "(\"SRS\") address here to protect against spoofing with our SRS domain name. We also check the recipient against our": "(\"SRS\") adres hier om te beschermen tegen spoofing met onze SRS-domeinnaam. We controleren de ontvanger ook tegen onze", + "- this is only applicable for outbound SMTP and correlates to the email ID stored in My Account → Emails": "- dit is alleen van toepassing op uitgaande SMTP en komt overeen met de e-mail-ID die is opgeslagen in Mijn account → E-mails", + "Bank Transfer": "Bankoverschrijving", + "Domestic Wire Transfer (Enterprise)": "Binnenlandse overschrijving (zakelijk)", + "International Wire Transfer (Enterprise)": "Internationale overschrijving (onderneming)" } \ No newline at end of file diff --git a/locales/no.json b/locales/no.json index 6675a4367..dc210a880 100644 --- a/locales/no.json +++ b/locales/no.json @@ -10159,5 +10159,104 @@ "Reviews, comparison, screenshots and more for the 80 best email services.": "Anmeldelser, sammenligning, skjermbilder og mer for de 80 beste e-posttjenestene.", "The Missing Email": "Den manglende e-posten", "14 Best Private Email Services in 2024": "14 beste private e-posttjenester i 2024", - "Reviews, comparison, screenshots and more for the 14 best private email services.": "Anmeldelser, sammenligning, skjermbilder og mer for de 14 beste private e-posttjenestene." + "Reviews, comparison, screenshots and more for the 14 best private email services.": "Anmeldelser, sammenligning, skjermbilder og mer for de 14 beste private e-posttjenestene.", + "Notice: API pagination required starting November 1st": "Merk: API-paginering kreves fra og med 1. november", + "Starting November 1st of this year we will be enforcing API pagination on our API endpoints for list domains and list domain aliases. Learn more about our approach to API pagination and how you can opt-in beforehand at %s.": "Fra 1. november i år vil vi håndheve API-paginering på API-endepunktene våre for listedomener og listedomenealiaser. Lær mer om vår tilnærming til API-paginering og hvordan du kan melde deg på på forhånd på %s .", + "Alias Contacts (CardDAV)": "Aliaskontakter (CardDAV)", + "List contacts": "Liste kontakter", + "Create contact": "Opprett kontakt", + "Retrieve contact": "Hent kontakt", + "Update contact": "Oppdater kontakt", + "Delete contact": "Slett kontakt", + "Alias Calendars (CalDAV)": "Alias-kalendere (CalDAV)", + "List calendars": "Liste kalendere", + "Create calendar": "Lag kalender", + "Retrieve calendar": "Hent kalender", + "Update calendar": "Oppdater kalenderen", + "Delete calendar": "Slett kalender", + "Alias Messages (IMAP/POP3)": "Aliasmeldinger (IMAP/POP3)", + "List and search for messages": "List og søk etter meldinger", + "Create message": "Lag melding", + "Retrieve message": "Hent melding", + "Update message": "Oppdater melding", + "Delete message": "Slett melding", + "Alias Folders (IMAP/POP3)": "Aliasmapper (IMAP/POP3)", + "List folders": "List mapper", + "Create folder": "Opprett mappe", + "Retrieve folder": "Hent mappe", + "Update folder": "Oppdater mappe", + "Delete folder": "Slett mappe", + "Copy folder": "Kopier mappe", + "Outbound Emails": "Utgående e-poster", + "Get outbound SMTP email limit": "Få utgående SMTP-e-postgrense", + "List outbound SMTP emails": "List ut utgående SMTP-e-poster", + "Create outbound SMTP email": "Opprett utgående SMTP-e-post", + "Retrieve outbound SMTP email": "Hent utgående SMTP-e-post", + "Delete outbound SMTP email": "Slett utgående SMTP-e-post", + "header (with the exception of": "header (med unntak av", + "Alias Contacts": "Alias kontakter", + "Alias Calendars": "Alias kalendere", + "Alias Mailboxes": "Alias postkasser", + "which use a": "som bruker en", + "generated alias username and password": "generert alias brukernavn og passord", + "Don't worry – examples are provided below for you if you're not sure what this is.": "Ikke bekymre deg – eksempler er gitt nedenfor for deg hvis du ikke er sikker på hva dette er.", + "As of November 1st, 2024 the API endpoints for": "Fra 1. november 2024 er API-endepunktene for", + "will default to": "vil som standard", + "max results per page. If you would like to opt-in to this behavior early, you can pass": "maks resultater per side. Hvis du ønsker å melde deg på denne atferden tidlig, kan du bestå", + "as an additional querystring parameter to the URL for the endpoint query.": "som en ekstra querystring-parameter til URL-en for endepunktspørringen.", + "Pagination is supported by all API endpoints that list results.": "Paginering støttes av alle API-endepunkter som viser resultater.", + "Simply provide the querystring properties": "Bare oppgi søkestrengegenskapene", + "(and optionally": "(og eventuelt", + "The property": "Eiendommen", + "should be a number greater than or equal to": "skal være et tall større enn eller lik", + ". If you provide": ". Hvis du gir", + "(also a number), then the minimum value is": "(også et tall), så er minimumsverdien", + "and maximum is": "og maksimum er", + "(unless otherwise noted).": "(med mindre annet er angitt).", + "Page of results to return. If not specified, the": "Side med resultater som skal returneres. Hvis ikke spesifisert, vil", + "value will be": "verdien vil være", + ". Must be a number greater than or equal to": ". Må være et tall større enn eller lik", + "Number of results to return per page. Defaults to": "Antall resultater å returnere per side. Standard til", + "if not specified. Must be a number greater than or equal to": "hvis ikke spesifisert. Må være et tall større enn eller lik", + ", and less than or equal to": ", og mindre enn eller lik", + "In order to determine whether or not more results are available, we provide these HTTP response headers (which you can parse in order to paginate programmatically):": "For å finne ut om flere resultater er tilgjengelige eller ikke, tilbyr vi disse HTTP-svarhodene (som du kan analysere for å paginere programmatisk):", + "HTTP Response Header": "HTTP-svarhode", + "The total page count available.": "Totalt antall sider tilgjengelig.", + "The current page of results returned (e.g. based off": "Den gjeldende siden med resultater returnert (f.eks. basert på", + "querystring parameter).": "spørrestrengparametere).", + "The total number of results in the page returned (e.g. based off": "Det totale antallet resultater på siden returnert (f.eks. basert på av", + "querystring parameter and actual results returned).": "querystring-parameter og faktiske resultater returnert).", + "The total number of items available across all pages.": "Det totale antallet varer som er tilgjengelig på alle sider.", + "We provide a": "Vi tilbyr en", + "HTTP response header you can parse as shown in the example. This is": "HTTP-svarhode du kan analysere som vist i eksemplet. Dette er", + "similar to GitHub": "ligner på GitHub", + "(e.g. not all values will be provided if they are not relevant or available, e.g.": "(f.eks. vil ikke alle verdier oppgis hvis de ikke er relevante eller tilgjengelige, f.eks.", + "will not be provided if there is not another page).": "vil ikke bli gitt hvis det ikke er en annen side).", + "Unlike other API endpoints, these require": "I motsetning til andre API-endepunkter krever disse", + "\"username\" equal to the alias username and \"password\" equal to the alias generated password as Basic Authorization headers.": "\"brukernavn\" lik aliasbrukernavnet og \"passord\" lik det aliasgenererte passordet som Basic Authorization-hoder.", + "This endpoint section is a work in progress and will be released (hopefully) in 2024. In the interim please use an IMAP client from the \"Apps\" dropdown in the navigation of our website.": "Denne endepunktseksjonen er under arbeid og vil bli utgitt (forhåpentligvis) i 2024. I mellomtiden vennligst bruk en IMAP-klient fra rullegardinmenyen \"Apper\" i navigasjonen på nettstedet vårt.", + "CardDAV support is not yet available, follow this discussion on GitHub for updates": "CardDAV-støtte er ennå ikke tilgjengelig, følg denne diskusjonen på GitHub for oppdateringer", + "Please ensure that you have followed setup instructions for your domain.": "Sørg for at du har fulgt oppsettinstruksjonene for domenet ditt.", + "These instructions can be found in our FAQ section": "Disse instruksjonene finner du i vår FAQ-seksjon", + "Do you support receiving email with IMAP?": "Støtter du mottak av e-post med IMAP?", + "This will": "Dette vil", + "send an email – it will only simply add the message to your mailbox folder (e.g. this is similar to the IMAP": "send en e-post – den vil bare legge til meldingen i postboksmappen din (dette ligner for eksempel på IMAP", + "command). If you would like to send an email, then see": "kommando). Hvis du vil sende en e-post, så se", + "below. After creating the outbound SMTP email, then you can append a copy of it using this endpoint to your alias' mailbox for storage purposes.": "under. Etter å ha opprettet den utgående SMTP-e-posten, kan du legge til en kopi av den ved å bruke dette endepunktet til aliasets postkasse for lagringsformål.", + "Folder endpoints with a folder's path": "Mappeendepunkter med en mappes bane", + "as their endpoint are interchangeable with a folder's ID": "ettersom endepunktet deres kan byttes ut med en mappes ID", + ". This means you can refer to the folder by either its": ". Dette betyr at du kan referere til mappen ved enten dens", + "These instructions can be found at": "Disse instruksjonene finner du på", + "Note that this endpoint does not return property values for an email's": "Merk at dette endepunktet ikke returnerer egenskapsverdier for en e-post", + "Sort by a specific field (prefix with a single hyphen": "Sorter etter et spesifikt felt (prefiks med en enkelt bindestrek", + "to sort in the reverse direction of that field). Defaults to": "for å sortere i motsatt retning av det feltet). Standard til", + "if not set.": "hvis ikke satt.", + "for more insight": "for mer innsikt", + "as their endpoint are interchangeable with a domain's ID": "ettersom endepunktet deres kan byttes ut med et domenes ID", + "as an additional querystring parameter to the URL for the endpoint query. See": "som en ekstra querystring-parameter til URL-en for endepunktspørringen. Se", + "(\"SRS\") address here to protect against spoofing with our SRS domain name. We also check the recipient against our": "(\"SRS\") adresse her for å beskytte mot forfalskning med vårt SRS-domenenavn. Vi sjekker også mottakeren mot vår", + "- this is only applicable for outbound SMTP and correlates to the email ID stored in My Account → Emails": "- dette gjelder kun for utgående SMTP og samsvarer med e-post-IDen som er lagret i Min konto → E-poster", + "Bank Transfer": "Bankoverføring", + "Domestic Wire Transfer (Enterprise)": "Innenlandsk bankoverføring (bedrift)", + "International Wire Transfer (Enterprise)": "Internasjonal bankoverføring (enterprise)" } \ No newline at end of file diff --git a/locales/pl.json b/locales/pl.json index ec42102d2..c82ff4454 100644 --- a/locales/pl.json +++ b/locales/pl.json @@ -10154,5 +10154,104 @@ "Reviews, comparison, screenshots and more for the 80 best email services.": "Recenzje, porównania, zrzuty ekranu i inne materiały dotyczące 80 najlepszych usług poczty e-mail.", "The Missing Email": "Brakujący e-mail", "14 Best Private Email Services in 2024": "14 najlepszych prywatnych usług e-mail w 2024", - "Reviews, comparison, screenshots and more for the 14 best private email services.": "Recenzje, porównania, zrzuty ekranu i inne materiały dotyczące 14 najlepszych usług poczty e-mail." + "Reviews, comparison, screenshots and more for the 14 best private email services.": "Recenzje, porównania, zrzuty ekranu i inne materiały dotyczące 14 najlepszych usług poczty e-mail.", + "Notice: API pagination required starting November 1st": "Uwaga: od 1 listopada wymagana będzie paginacja API", + "Starting November 1st of this year we will be enforcing API pagination on our API endpoints for list domains and list domain aliases. Learn more about our approach to API pagination and how you can opt-in beforehand at %s.": "Od 1 listopada tego roku będziemy egzekwować paginację API w naszych punktach końcowych API dla domen list i aliasów domen list. Dowiedz się więcej o naszym podejściu do paginacji API i jak możesz wcześniej się na nią zdecydować na %s .", + "Alias Contacts (CardDAV)": "Alias Kontakty (CardDAV)", + "List contacts": "Lista kontaktów", + "Create contact": "Utwórz kontakt", + "Retrieve contact": "Pobierz kontakt", + "Update contact": "Aktualizuj kontakt", + "Delete contact": "Usuń kontakt", + "Alias Calendars (CalDAV)": "Kalendarze aliasowe (CalDAV)", + "List calendars": "Lista kalendarzy", + "Create calendar": "Utwórz kalendarz", + "Retrieve calendar": "Pobierz kalendarz", + "Update calendar": "Aktualizuj kalendarz", + "Delete calendar": "Usuń kalendarz", + "Alias Messages (IMAP/POP3)": "Wiadomości aliasowe (IMAP/POP3)", + "List and search for messages": "Lista i wyszukiwanie wiadomości", + "Create message": "Utwórz wiadomość", + "Retrieve message": "Pobierz wiadomość", + "Update message": "Aktualizuj wiadomość", + "Delete message": "Usuń wiadomość", + "Alias Folders (IMAP/POP3)": "Foldery aliasowe (IMAP/POP3)", + "List folders": "Wyświetlanie listy folderów", + "Create folder": "Utwórz folder", + "Retrieve folder": "Pobierz folder", + "Update folder": "Aktualizuj folder", + "Delete folder": "Usuń folder", + "Copy folder": "Kopiuj folder", + "Outbound Emails": "Wiadomości e-mail wychodzące", + "Get outbound SMTP email limit": "Uzyskaj limit poczty wychodzącej SMTP", + "List outbound SMTP emails": "Wyświetl listę wiadomości e-mail SMTP wychodzących", + "Create outbound SMTP email": "Utwórz wychodzącą pocztę SMTP", + "Retrieve outbound SMTP email": "Pobierz wychodzącą pocztę SMTP", + "Delete outbound SMTP email": "Usuń wychodzącą pocztę SMTP", + "header (with the exception of": "nagłówek (z wyjątkiem", + "Alias Contacts": "Alias Kontakty", + "Alias Calendars": "Kalendarze Alias", + "Alias Mailboxes": "Skrzynki pocztowe Alias", + "which use a": "które używają", + "generated alias username and password": "wygenerowany alias nazwa użytkownika i hasło", + "Don't worry – examples are provided below for you if you're not sure what this is.": "Nie martw się – jeśli nie jesteś pewien, o co chodzi, poniżej znajdziesz przykłady.", + "As of November 1st, 2024 the API endpoints for": "Od 1 listopada 2024 r. punkty końcowe interfejsu API dla", + "will default to": "domyślnie będzie", + "max results per page. If you would like to opt-in to this behavior early, you can pass": "maks. wyników na stronę. Jeśli chcesz wcześnie włączyć się do tego zachowania, możesz przejść", + "as an additional querystring parameter to the URL for the endpoint query.": "jako dodatkowy parametr ciągu zapytania do adresu URL dla zapytania punktu końcowego.", + "Pagination is supported by all API endpoints that list results.": "Paginacja jest obsługiwana przez wszystkie punkty końcowe API, które wyświetlają wyniki.", + "Simply provide the querystring properties": "Wystarczy podać właściwości ciągu zapytania", + "(and optionally": "(i opcjonalnie", + "The property": "Nieruchomość", + "should be a number greater than or equal to": "powinna być liczbą większą lub równą", + ". If you provide": ". Jeśli podasz", + "(also a number), then the minimum value is": "(również liczba), wówczas minimalna wartość to", + "and maximum is": "a maksimum to", + "(unless otherwise noted).": "(chyba że zaznaczono inaczej).", + "Page of results to return. If not specified, the": "Strona wyników do zwrócenia. Jeśli nie określono,", + "value will be": "wartość będzie", + ". Must be a number greater than or equal to": ". Musi być liczbą większą lub równą", + "Number of results to return per page. Defaults to": "Liczba wyników do zwrócenia na stronę. Domyślnie", + "if not specified. Must be a number greater than or equal to": "jeśli nie określono. Musi być liczbą większą lub równą", + ", and less than or equal to": "i mniejsze lub równe", + "In order to determine whether or not more results are available, we provide these HTTP response headers (which you can parse in order to paginate programmatically):": "Aby ustalić, czy dostępnych jest więcej wyników, udostępniamy następujące nagłówki odpowiedzi HTTP (które można przeanalizować w celu programowego podziału na strony):", + "HTTP Response Header": "Nagłówek odpowiedzi HTTP", + "The total page count available.": "Całkowita liczba dostępnych stron.", + "The current page of results returned (e.g. based off": "Bieżąca strona zwróconych wyników (np. na podstawie", + "querystring parameter).": "parametry zapytania).", + "The total number of results in the page returned (e.g. based off": "Całkowita liczba wyników zwróconych na stronie (np. na podstawie", + "querystring parameter and actual results returned).": "parametr ciągu zapytania i zwrócone rzeczywiste wyniki).", + "The total number of items available across all pages.": "Łączna liczba elementów dostępnych na wszystkich stronach.", + "We provide a": "Zapewniamy", + "HTTP response header you can parse as shown in the example. This is": "Nagłówek odpowiedzi HTTP możesz przeanalizować tak, jak pokazano w przykładzie. To jest", + "similar to GitHub": "podobnie do GitHub", + "(e.g. not all values will be provided if they are not relevant or available, e.g.": "(np. nie wszystkie wartości zostaną podane, jeśli nie są istotne lub dostępne, np.", + "will not be provided if there is not another page).": "nie będzie dostępna, jeśli nie ma innej strony).", + "Unlike other API endpoints, these require": "W przeciwieństwie do innych punktów końcowych interfejsu API, te wymagają", + "\"username\" equal to the alias username and \"password\" equal to the alias generated password as Basic Authorization headers.": "„username” równa się aliasowi nazwy użytkownika, a „password” równa się aliasowi wygenerowanemu hasłu jako nagłówki podstawowej autoryzacji.", + "This endpoint section is a work in progress and will be released (hopefully) in 2024. In the interim please use an IMAP client from the \"Apps\" dropdown in the navigation of our website.": "Ta sekcja punktu końcowego jest w trakcie realizacji i zostanie wydana (miejmy nadzieję) w 2024 r. W międzyczasie prosimy o korzystanie z klienta IMAP z rozwijanego menu „Aplikacje” w nawigacji naszej witryny.", + "CardDAV support is not yet available, follow this discussion on GitHub for updates": "Obsługa CardDAV nie jest jeszcze dostępna. Aby uzyskać aktualizacje, śledź tę dyskusję na GitHub", + "Please ensure that you have followed setup instructions for your domain.": "Upewnij się, że wykonałeś/aś instrukcje konfiguracji dla swojej domeny.", + "These instructions can be found in our FAQ section": "Instrukcje te można znaleźć w naszej sekcji FAQ", + "Do you support receiving email with IMAP?": "Czy obsługujecie odbieranie poczty elektronicznej za pomocą protokołu IMAP?", + "This will": "To będzie", + "send an email – it will only simply add the message to your mailbox folder (e.g. this is similar to the IMAP": "wyślij wiadomość e-mail – wiadomość zostanie po prostu dodana do folderu skrzynki pocztowej (np. jest to podobne do IMAP)", + "command). If you would like to send an email, then see": "polecenie). Jeśli chcesz wysłać e-mail, zobacz", + "below. After creating the outbound SMTP email, then you can append a copy of it using this endpoint to your alias' mailbox for storage purposes.": "poniżej. Po utworzeniu wychodzącej wiadomości e-mail SMTP możesz dołączyć jej kopię za pomocą tego punktu końcowego do skrzynki pocztowej swojego aliasu w celu przechowywania.", + "Folder endpoints with a folder's path": "Punkty końcowe folderów ze ścieżką folderu", + "as their endpoint are interchangeable with a folder's ID": "ponieważ ich punkt końcowy jest wymienny z identyfikatorem folderu", + ". This means you can refer to the folder by either its": "Oznacza to, że do folderu można odwołać się albo poprzez jego", + "These instructions can be found at": "Instrukcje te można znaleźć pod adresem", + "Note that this endpoint does not return property values for an email's": "Należy pamiętać, że ten punkt końcowy nie zwraca wartości właściwości dla wiadomości e-mail.", + "Sort by a specific field (prefix with a single hyphen": "Sortuj według określonego pola (prefiks z pojedynczym myślnikiem)", + "to sort in the reverse direction of that field). Defaults to": "aby posortować w odwrotnym kierunku niż to pole). Domyślnie", + "if not set.": "jeśli nie ustawiono.", + "for more insight": "aby uzyskać więcej informacji", + "as their endpoint are interchangeable with a domain's ID": "ponieważ ich punkt końcowy jest wymienny z identyfikatorem domeny", + "as an additional querystring parameter to the URL for the endpoint query. See": "jako dodatkowy parametr ciągu zapytania do adresu URL dla zapytania punktu końcowego. Zobacz", + "(\"SRS\") address here to protect against spoofing with our SRS domain name. We also check the recipient against our": "(„SRS”) adres tutaj, aby chronić przed podszywaniem się pod naszą nazwę domeny SRS. Sprawdzamy również odbiorcę w stosunku do naszej", + "- this is only applicable for outbound SMTP and correlates to the email ID stored in My Account → Emails": "- dotyczy to tylko wychodzącego SMTP i jest powiązane z identyfikatorem e-mail zapisanym w Moim koncie → E-maile", + "Bank Transfer": "Przelew bankowy", + "Domestic Wire Transfer (Enterprise)": "Przelew krajowy (Enterprise)", + "International Wire Transfer (Enterprise)": "Międzynarodowy przelew bankowy (Enterprise)" } \ No newline at end of file diff --git a/locales/pt.json b/locales/pt.json index c56b5a4b6..85a3ec3ff 100644 --- a/locales/pt.json +++ b/locales/pt.json @@ -10154,5 +10154,104 @@ "Reviews, comparison, screenshots and more for the 80 best email services.": "Avaliações, comparações, capturas de tela e muito mais dos 80 melhores serviços de e-mail.", "The Missing Email": "O e-mail perdido", "14 Best Private Email Services in 2024": "14 melhores serviços de e-mail privado em 2024", - "Reviews, comparison, screenshots and more for the 14 best private email services.": "Avaliações, comparações, capturas de tela e muito mais dos 14 melhores serviços de e-mail privado." + "Reviews, comparison, screenshots and more for the 14 best private email services.": "Avaliações, comparações, capturas de tela e muito mais dos 14 melhores serviços de e-mail privado.", + "Notice: API pagination required starting November 1st": "Aviso: paginação de API necessária a partir de 1º de novembro", + "Starting November 1st of this year we will be enforcing API pagination on our API endpoints for list domains and list domain aliases. Learn more about our approach to API pagination and how you can opt-in beforehand at %s.": "A partir de 1º de novembro deste ano, aplicaremos a paginação de API em nossos endpoints de API para domínios de lista e aliases de domínio de lista. Saiba mais sobre nossa abordagem para paginação de API e como você pode optar por participar antecipadamente em %s .", + "Alias Contacts (CardDAV)": "Contatos de Alias (CardDAV)", + "List contacts": "Listar contatos", + "Create contact": "Criar contato", + "Retrieve contact": "Recuperar contato", + "Update contact": "Atualizar contato", + "Delete contact": "Excluir contato", + "Alias Calendars (CalDAV)": "Calendários Alias (CalDAV)", + "List calendars": "Listar calendários", + "Create calendar": "Criar calendário", + "Retrieve calendar": "Recuperar calendário", + "Update calendar": "Atualizar calendário", + "Delete calendar": "Excluir calendário", + "Alias Messages (IMAP/POP3)": "Mensagens de Alias (IMAP/POP3)", + "List and search for messages": "Listar e pesquisar mensagens", + "Create message": "Criar mensagem", + "Retrieve message": "Recuperar mensagem", + "Update message": "Mensagem de atualização", + "Delete message": "Apagar mensagem", + "Alias Folders (IMAP/POP3)": "Pastas de Alias (IMAP/POP3)", + "List folders": "Listar pastas", + "Create folder": "Criar pasta", + "Retrieve folder": "Recuperar pasta", + "Update folder": "Atualizar pasta", + "Delete folder": "Excluir pasta", + "Copy folder": "Copiar pasta", + "Outbound Emails": "E-mails de saída", + "Get outbound SMTP email limit": "Obtenha limite de e-mail SMTP de saída", + "List outbound SMTP emails": "Listar e-mails SMTP de saída", + "Create outbound SMTP email": "Criar e-mail SMTP de saída", + "Retrieve outbound SMTP email": "Recuperar e-mail SMTP de saída", + "Delete outbound SMTP email": "Excluir e-mail SMTP de saída", + "header (with the exception of": "cabeçalho (com exceção de", + "Alias Contacts": "Contatos de Alias", + "Alias Calendars": "Calendários Alias", + "Alias Mailboxes": "Caixas de correio de alias", + "which use a": "que usam um", + "generated alias username and password": "nome de usuário e senha de alias gerados", + "Don't worry – examples are provided below for you if you're not sure what this is.": "Não se preocupe – abaixo fornecemos exemplos para você caso não tenha certeza do que é isso.", + "As of November 1st, 2024 the API endpoints for": "A partir de 1º de novembro de 2024, os endpoints da API para", + "will default to": "será o padrão para", + "max results per page. If you would like to opt-in to this behavior early, you can pass": "máximo de resultados por página. Se você quiser optar por esse comportamento antecipadamente, você pode passar", + "as an additional querystring parameter to the URL for the endpoint query.": "como um parâmetro de string de consulta adicional para a URL da consulta do ponto de extremidade.", + "Pagination is supported by all API endpoints that list results.": "A paginação é suportada por todos os endpoints de API que listam resultados.", + "Simply provide the querystring properties": "Basta fornecer as propriedades da string de consulta", + "(and optionally": "(e opcionalmente", + "The property": "A propriedade", + "should be a number greater than or equal to": "deve ser um número maior ou igual a", + ". If you provide": ". Se você fornecer", + "(also a number), then the minimum value is": "(também um número), então o valor mínimo é", + "and maximum is": "e o máximo é", + "(unless otherwise noted).": "(salvo indicação em contrário).", + "Page of results to return. If not specified, the": "Página de resultados a retornar. Se não for especificado, o", + "value will be": "valor será", + ". Must be a number greater than or equal to": ". Deve ser um número maior ou igual a", + "Number of results to return per page. Defaults to": "Número de resultados a serem retornados por página. O padrão é", + "if not specified. Must be a number greater than or equal to": "se não for especificado. Deve ser um número maior ou igual a", + ", and less than or equal to": ", e menor ou igual a", + "In order to determine whether or not more results are available, we provide these HTTP response headers (which you can parse in order to paginate programmatically):": "Para determinar se há mais resultados disponíveis, fornecemos estes cabeçalhos de resposta HTTP (que você pode analisar para paginar programaticamente):", + "HTTP Response Header": "Cabeçalho de resposta HTTP", + "The total page count available.": "Contagem total de páginas disponíveis.", + "The current page of results returned (e.g. based off": "A página atual de resultados retornados (por exemplo, com base em", + "querystring parameter).": "parâmetros de string de consulta).", + "The total number of results in the page returned (e.g. based off": "O número total de resultados na página retornados (por exemplo, com base em", + "querystring parameter and actual results returned).": "parâmetro querystring e resultados reais retornados).", + "The total number of items available across all pages.": "O número total de itens disponíveis em todas as páginas.", + "We provide a": "Nós fornecemos um", + "HTTP response header you can parse as shown in the example. This is": "Cabeçalho de resposta HTTP que você pode analisar conforme mostrado no exemplo. Isto é", + "similar to GitHub": "semelhante ao GitHub", + "(e.g. not all values will be provided if they are not relevant or available, e.g.": "(por exemplo, nem todos os valores serão fornecidos se não forem relevantes ou não estiverem disponíveis, por exemplo", + "will not be provided if there is not another page).": "não será fornecido se não houver outra página).", + "Unlike other API endpoints, these require": "Ao contrário de outros endpoints de API, estes requerem", + "\"username\" equal to the alias username and \"password\" equal to the alias generated password as Basic Authorization headers.": "\"nome de usuário\" igual ao nome de usuário do alias e \"senha\" igual à senha gerada pelo alias como cabeçalhos de Autorização Básica.", + "This endpoint section is a work in progress and will be released (hopefully) in 2024. In the interim please use an IMAP client from the \"Apps\" dropdown in the navigation of our website.": "Esta seção de endpoint é um trabalho em andamento e será lançada (espero) em 2024. Enquanto isso, use um cliente IMAP no menu suspenso \"Aplicativos\" na navegação do nosso site.", + "CardDAV support is not yet available, follow this discussion on GitHub for updates": "O suporte a CardDAV ainda não está disponível, siga esta discussão no GitHub para atualizações", + "Please ensure that you have followed setup instructions for your domain.": "Certifique-se de ter seguido as instruções de configuração do seu domínio.", + "These instructions can be found in our FAQ section": "Essas instruções podem ser encontradas em nossa seção de perguntas frequentes", + "Do you support receiving email with IMAP?": "Vocês oferecem suporte para receber e-mails com IMAP?", + "This will": "Isto irá", + "send an email – it will only simply add the message to your mailbox folder (e.g. this is similar to the IMAP": "envie um e-mail – ele simplesmente adicionará a mensagem à sua pasta de caixa de correio (por exemplo, isso é semelhante ao IMAP", + "command). If you would like to send an email, then see": "comando). Se você quiser enviar um e-mail, veja", + "below. After creating the outbound SMTP email, then you can append a copy of it using this endpoint to your alias' mailbox for storage purposes.": "abaixo. Após criar o e-mail SMTP de saída, você pode anexar uma cópia dele usando este endpoint à caixa de correio do seu alias para fins de armazenamento.", + "Folder endpoints with a folder's path": "Pontos finais de pasta com o caminho de uma pasta", + "as their endpoint are interchangeable with a folder's ID": "como seu ponto final são intercambiáveis com o ID de uma pasta", + ". This means you can refer to the folder by either its": ". Isso significa que você pode consultar a pasta por meio de seu", + "These instructions can be found at": "Estas instruções podem ser encontradas em", + "Note that this endpoint does not return property values for an email's": "Observe que este ponto de extremidade não retorna valores de propriedade para um e-mail", + "Sort by a specific field (prefix with a single hyphen": "Classificar por um campo específico (prefixo com um único hífen", + "to sort in the reverse direction of that field). Defaults to": "para classificar na direção reversa desse campo). O padrão é", + "if not set.": "se não estiver definido.", + "for more insight": "para mais informações", + "as their endpoint are interchangeable with a domain's ID": "como seu ponto final é intercambiável com o ID de um domínio", + "as an additional querystring parameter to the URL for the endpoint query. See": "como um parâmetro querystring adicional para a URL para a consulta do ponto de extremidade. Veja", + "(\"SRS\") address here to protect against spoofing with our SRS domain name. We also check the recipient against our": "(\"SRS\") aqui para proteger contra falsificação com nosso nome de domínio SRS. Também verificamos o destinatário em relação ao nosso", + "- this is only applicable for outbound SMTP and correlates to the email ID stored in My Account → Emails": "- isso só se aplica ao SMTP de saída e se correlaciona com o ID de e-mail armazenado em Minha conta → E-mails", + "Bank Transfer": "Transferência bancária", + "Domestic Wire Transfer (Enterprise)": "Transferência bancária nacional (empresarial)", + "International Wire Transfer (Enterprise)": "Transferência bancária internacional (empresarial)" } \ No newline at end of file diff --git a/locales/ru.json b/locales/ru.json index e30b4c2cd..f35ad4843 100644 --- a/locales/ru.json +++ b/locales/ru.json @@ -10154,5 +10154,104 @@ "Reviews, comparison, screenshots and more for the 80 best email services.": "Обзоры, сравнения, скриншоты и многое другое для 80 лучших почтовых сервисов.", "The Missing Email": "Пропавшее электронное письмо", "14 Best Private Email Services in 2024": "14 лучших частных почтовых сервисов в 2024", - "Reviews, comparison, screenshots and more for the 14 best private email services.": "Обзоры, сравнения, скриншоты и многое другое для 14 лучших сервисов частной электронной почты." + "Reviews, comparison, screenshots and more for the 14 best private email services.": "Обзоры, сравнения, скриншоты и многое другое для 14 лучших сервисов частной электронной почты.", + "Notice: API pagination required starting November 1st": "Примечание: с 1 ноября требуется разбиение API на страницы", + "Starting November 1st of this year we will be enforcing API pagination on our API endpoints for list domains and list domain aliases. Learn more about our approach to API pagination and how you can opt-in beforehand at %s.": "Начиная с 1 ноября этого года мы будем принудительно применять API-пагинацию на наших конечных точках API для доменов списков и псевдонимов доменов списков. Узнайте больше о нашем подходе к API-пагинации и о том, как вы можете заранее подписаться на %s .", + "Alias Contacts (CardDAV)": "Контакты псевдонима (CardDAV)", + "List contacts": "Список контактов", + "Create contact": "Создать контакт", + "Retrieve contact": "Получить контакт", + "Update contact": "Обновить контакт", + "Delete contact": "Удалить контакт", + "Alias Calendars (CalDAV)": "Календари псевдонимов (CalDAV)", + "List calendars": "Список календарей", + "Create calendar": "Создать календарь", + "Retrieve calendar": "Получить календарь", + "Update calendar": "Календарь обновлений", + "Delete calendar": "Удалить календарь", + "Alias Messages (IMAP/POP3)": "Сообщения псевдонимов (IMAP/POP3)", + "List and search for messages": "Список и поиск сообщений", + "Create message": "Создать сообщение", + "Retrieve message": "Получить сообщение", + "Update message": "Обновить сообщение", + "Delete message": "Удалить сообщение", + "Alias Folders (IMAP/POP3)": "Псевдонимы папок (IMAP/POP3)", + "List folders": "Список папок", + "Create folder": "Создать папку", + "Retrieve folder": "Восстановить папку", + "Update folder": "Обновить папку", + "Delete folder": "Удалить папку", + "Copy folder": "Копировать папку", + "Outbound Emails": "Исходящие электронные письма", + "Get outbound SMTP email limit": "Получить лимит исходящей электронной почты SMTP", + "List outbound SMTP emails": "Список исходящих писем SMTP", + "Create outbound SMTP email": "Создать исходящее SMTP-сообщение", + "Retrieve outbound SMTP email": "Получить исходящую SMTP-почту", + "Delete outbound SMTP email": "Удалить исходящую SMTP-почту", + "header (with the exception of": "заголовок (за исключением", + "Alias Contacts": "Контакты псевдонима", + "Alias Calendars": "Псевдонимы Календари", + "Alias Mailboxes": "Псевдонимы почтовых ящиков", + "which use a": "которые используют", + "generated alias username and password": "сгенерированный псевдоним имени пользователя и пароля", + "Don't worry – examples are provided below for you if you're not sure what this is.": "Не волнуйтесь — ниже приведены примеры, если вы не уверены, что это такое.", + "As of November 1st, 2024 the API endpoints for": "По состоянию на 1 ноября 2024 года конечные точки API для", + "will default to": "по умолчанию будет", + "max results per page. If you would like to opt-in to this behavior early, you can pass": "максимальное количество результатов на странице. Если вы хотите заранее подписаться на это поведение, вы можете передать", + "as an additional querystring parameter to the URL for the endpoint query.": "как дополнительный параметр строки запроса к URL-адресу для запроса конечной точки.", + "Pagination is supported by all API endpoints that list results.": "Пагинация поддерживается всеми конечными точками API, выводящими список результатов.", + "Simply provide the querystring properties": "Просто укажите свойства строки запроса", + "(and optionally": "(и по желанию", + "The property": "Собственность", + "should be a number greater than or equal to": "должно быть числом большим или равным", + ". If you provide": ". Если вы предоставите", + "(also a number), then the minimum value is": "(также число), то минимальное значение равно", + "and maximum is": "и максимум - это", + "(unless otherwise noted).": "(если не указано иное).", + "Page of results to return. If not specified, the": "Страница результатов для возврата. Если не указано,", + "value will be": "значение будет", + ". Must be a number greater than or equal to": ". Должно быть число больше или равное", + "Number of results to return per page. Defaults to": "Количество результатов для возврата на страницу. По умолчанию", + "if not specified. Must be a number greater than or equal to": "если не указано. Должно быть число больше или равно", + ", and less than or equal to": ", и меньше или равно", + "In order to determine whether or not more results are available, we provide these HTTP response headers (which you can parse in order to paginate programmatically):": "Чтобы определить, доступны ли дополнительные результаты, мы предоставляем следующие заголовки HTTP-ответа (которые можно проанализировать для программной разбивки на страницы):", + "HTTP Response Header": "Заголовок HTTP-ответа", + "The total page count available.": "Общее количество доступных страниц.", + "The current page of results returned (e.g. based off": "Текущая страница результатов возвращается (например, на основе", + "querystring parameter).": "параметры строки запроса).", + "The total number of results in the page returned (e.g. based off": "Общее количество результатов на возвращенной странице (например, на основе", + "querystring parameter and actual results returned).": "параметр строки запроса и фактические возвращаемые результаты).", + "The total number of items available across all pages.": "Общее количество элементов, доступных на всех страницах.", + "We provide a": "Мы предоставляем", + "HTTP response header you can parse as shown in the example. This is": "Заголовок ответа HTTP можно проанализировать, как показано в примере. Это", + "similar to GitHub": "похоже на GitHub", + "(e.g. not all values will be provided if they are not relevant or available, e.g.": "(например, не все значения будут предоставлены, если они нерелевантны или недоступны, например", + "will not be provided if there is not another page).": "не будет предоставлен, если нет другой страницы).", + "Unlike other API endpoints, these require": "В отличие от других конечных точек API, эти требуют", + "\"username\" equal to the alias username and \"password\" equal to the alias generated password as Basic Authorization headers.": "«username» равно псевдониму имени пользователя, а «password» равно паролю, сгенерированному псевдонимом, в качестве заголовков базовой авторизации.", + "This endpoint section is a work in progress and will be released (hopefully) in 2024. In the interim please use an IMAP client from the \"Apps\" dropdown in the navigation of our website.": "Этот раздел конечной точки находится в стадии разработки и будет выпущен (надеюсь) в 2024 году. В это время используйте, пожалуйста, клиент IMAP из раскрывающегося списка «Приложения» в навигации нашего веб-сайта.", + "CardDAV support is not yet available, follow this discussion on GitHub for updates": "Поддержка CardDAV пока недоступна, следите за обновлениями в этом обсуждении на GitHub", + "Please ensure that you have followed setup instructions for your domain.": "Убедитесь, что вы выполнили инструкции по настройке вашего домена.", + "These instructions can be found in our FAQ section": "Эти инструкции можно найти в разделе часто задаваемых вопросов.", + "Do you support receiving email with IMAP?": "Поддерживаете ли вы получение электронной почты по протоколу IMAP?", + "This will": "Это будет", + "send an email – it will only simply add the message to your mailbox folder (e.g. this is similar to the IMAP": "отправить электронное письмо – оно просто добавит сообщение в папку вашего почтового ящика (например, это похоже на IMAP)", + "command). If you would like to send an email, then see": "Команда). Если вы хотите отправить электронное письмо, см.", + "below. After creating the outbound SMTP email, then you can append a copy of it using this endpoint to your alias' mailbox for storage purposes.": "ниже. После создания исходящего SMTP-письма вы можете прикрепить его копию, используя эту конечную точку, к почтовому ящику вашего псевдонима для хранения.", + "Folder endpoints with a folder's path": "Конечные точки папок с путем к папке", + "as their endpoint are interchangeable with a folder's ID": "поскольку их конечная точка взаимозаменяема с идентификатором папки", + ". This means you can refer to the folder by either its": ". Это означает, что вы можете ссылаться на папку либо по ее имени,", + "These instructions can be found at": "Эти инструкции можно найти по адресу", + "Note that this endpoint does not return property values for an email's": "Обратите внимание, что эта конечная точка не возвращает значения свойств для адреса электронной почты.", + "Sort by a specific field (prefix with a single hyphen": "Сортировать по определенному полю (префикс с одним дефисом)", + "to sort in the reverse direction of that field). Defaults to": "для сортировки в обратном направлении этого поля). По умолчанию", + "if not set.": "если не установлено.", + "for more insight": "для более глубокого понимания", + "as their endpoint are interchangeable with a domain's ID": "поскольку их конечная точка взаимозаменяема с идентификатором домена", + "as an additional querystring parameter to the URL for the endpoint query. See": "как дополнительный параметр строки запроса к URL для запроса конечной точки. См.", + "(\"SRS\") address here to protect against spoofing with our SRS domain name. We also check the recipient against our": "(\"SRS\") адрес здесь для защиты от подмены с нашим доменным именем SRS. Мы также проверяем получателя по нашему", + "- this is only applicable for outbound SMTP and correlates to the email ID stored in My Account → Emails": "- это применимо только для исходящего SMTP и соответствует идентификатору электронной почты, сохраненному в разделе «Моя учетная запись» → «Электронная почта».", + "Bank Transfer": "Банковский перевод", + "Domestic Wire Transfer (Enterprise)": "Внутренний банковский перевод (корпоративный)", + "International Wire Transfer (Enterprise)": "Международный банковский перевод (корпоративный)" } \ No newline at end of file diff --git a/locales/sv.json b/locales/sv.json index d1511937f..b80326a95 100644 --- a/locales/sv.json +++ b/locales/sv.json @@ -10154,5 +10154,104 @@ "Reviews, comparison, screenshots and more for the 80 best email services.": "Recensioner, jämförelse, skärmdumpar och mer för de 80 bästa e-posttjänsterna.", "The Missing Email": "Det saknade e-postmeddelandet", "14 Best Private Email Services in 2024": "14 bästa privata e-posttjänster 2024", - "Reviews, comparison, screenshots and more for the 14 best private email services.": "Recensioner, jämförelse, skärmdumpar och mer för de 14 bästa privata e-posttjänsterna." + "Reviews, comparison, screenshots and more for the 14 best private email services.": "Recensioner, jämförelse, skärmdumpar och mer för de 14 bästa privata e-posttjänsterna.", + "Notice: API pagination required starting November 1st": "Observera: API-paginering krävs från och med 1 november", + "Starting November 1st of this year we will be enforcing API pagination on our API endpoints for list domains and list domain aliases. Learn more about our approach to API pagination and how you can opt-in beforehand at %s.": "Från och med den 1 november i år kommer vi att tillämpa API-paginering på våra API-slutpunkter för listdomäner och listdomänalias. Läs mer om vårt tillvägagångssätt för API-paginering och hur du kan anmäla dig i förväg på %s .", + "Alias Contacts (CardDAV)": "Aliaskontakter (CardDAV)", + "List contacts": "Lista kontakter", + "Create contact": "Skapa kontakt", + "Retrieve contact": "Hämta kontakt", + "Update contact": "Uppdatera kontakt", + "Delete contact": "Ta bort kontakt", + "Alias Calendars (CalDAV)": "Alias kalendrar (CalDAV)", + "List calendars": "Lista kalendrar", + "Create calendar": "Skapa kalender", + "Retrieve calendar": "Hämta kalender", + "Update calendar": "Uppdatera kalender", + "Delete calendar": "Ta bort kalender", + "Alias Messages (IMAP/POP3)": "Aliasmeddelanden (IMAP/POP3)", + "List and search for messages": "Lista och sök efter meddelanden", + "Create message": "Skapa meddelande", + "Retrieve message": "Hämta meddelande", + "Update message": "Uppdatera meddelande", + "Delete message": "Ta bort meddelande", + "Alias Folders (IMAP/POP3)": "Alias mappar (IMAP/POP3)", + "List folders": "Lista mappar", + "Create folder": "Skapa mapp", + "Retrieve folder": "Hämta mapp", + "Update folder": "Uppdatera mapp", + "Delete folder": "Ta bort mapp", + "Copy folder": "Kopiera mapp", + "Outbound Emails": "Utgående e-postmeddelanden", + "Get outbound SMTP email limit": "Få utgående SMTP-e-postgräns", + "List outbound SMTP emails": "Lista utgående SMTP-e-postmeddelanden", + "Create outbound SMTP email": "Skapa utgående SMTP-e-post", + "Retrieve outbound SMTP email": "Hämta utgående SMTP-e-post", + "Delete outbound SMTP email": "Ta bort utgående SMTP-e-post", + "header (with the exception of": "header (med undantag för", + "Alias Contacts": "Alias kontakter", + "Alias Calendars": "Alias kalendrar", + "Alias Mailboxes": "Alias brevlådor", + "which use a": "som använder en", + "generated alias username and password": "genererat alias användarnamn och lösenord", + "Don't worry – examples are provided below for you if you're not sure what this is.": "Oroa dig inte – exempel ges nedan för dig om du inte är säker på vad detta är.", + "As of November 1st, 2024 the API endpoints for": "Från och med den 1 november 2024 är API-slutpunkterna för", + "will default to": "kommer som standard till", + "max results per page. If you would like to opt-in to this behavior early, you can pass": "max resultat per sida. Om du vill välja detta beteende tidigt kan du gå igenom", + "as an additional querystring parameter to the URL for the endpoint query.": "som en extra frågesträngsparameter till URL:en för ändpunktsfrågan.", + "Pagination is supported by all API endpoints that list results.": "Paginering stöds av alla API-slutpunkter som visar resultat.", + "Simply provide the querystring properties": "Ange helt enkelt querystring-egenskaperna", + "(and optionally": "(och valfritt", + "The property": "Fastigheten", + "should be a number greater than or equal to": "bör vara ett tal större än eller lika med", + ". If you provide": ". Om du tillhandahåller", + "(also a number), then the minimum value is": "(också ett tal), då är minimivärdet", + "and maximum is": "och maximum är", + "(unless otherwise noted).": "(om inget annat anges).", + "Page of results to return. If not specified, the": "Sida med resultat att returnera. Om det inte anges,", + "value will be": "värde kommer att vara", + ". Must be a number greater than or equal to": ". Måste vara ett tal större än eller lika med", + "Number of results to return per page. Defaults to": "Antal resultat att returnera per sida. Standard till", + "if not specified. Must be a number greater than or equal to": "om inte specificerat. Måste vara ett tal större än eller lika med", + ", and less than or equal to": ", och mindre än eller lika med", + "In order to determine whether or not more results are available, we provide these HTTP response headers (which you can parse in order to paginate programmatically):": "För att avgöra om fler resultat är tillgängliga eller inte, tillhandahåller vi dessa HTTP-svarsrubriker (som du kan tolka för att paginera programmatiskt):", + "HTTP Response Header": "HTTP-svarshuvud", + "The total page count available.": "Det totala antalet tillgängliga sidor.", + "The current page of results returned (e.g. based off": "Den aktuella sidan med resultat som returneras (t.ex. baserat på", + "querystring parameter).": "frågesträngsparametrar).", + "The total number of results in the page returned (e.g. based off": "Det totala antalet resultat på sidan som returneras (t.ex. baserat på", + "querystring parameter and actual results returned).": "querystring-parameter och faktiska resultat som returneras).", + "The total number of items available across all pages.": "Det totala antalet artiklar som är tillgängliga på alla sidor.", + "We provide a": "Vi tillhandahåller en", + "HTTP response header you can parse as shown in the example. This is": "HTTP-svarshuvud som du kan analysera som visas i exemplet. Detta är", + "similar to GitHub": "liknande GitHub", + "(e.g. not all values will be provided if they are not relevant or available, e.g.": "(t.ex. kommer inte alla värden att tillhandahållas om de inte är relevanta eller tillgängliga, t.ex.", + "will not be provided if there is not another page).": "kommer inte att tillhandahållas om det inte finns en annan sida).", + "Unlike other API endpoints, these require": "Till skillnad från andra API-slutpunkter kräver dessa", + "\"username\" equal to the alias username and \"password\" equal to the alias generated password as Basic Authorization headers.": "\"användarnamn\" lika med alias användarnamn och \"lösenord\" lika med det alias genererade lösenordet som Basic Authorization headers.", + "This endpoint section is a work in progress and will be released (hopefully) in 2024. In the interim please use an IMAP client from the \"Apps\" dropdown in the navigation of our website.": "Denna slutpunktssektion är ett pågående arbete och kommer att släppas (förhoppningsvis) 2024. Under tiden, använd en IMAP-klient från rullgardinsmenyn \"Appar\" i navigeringen på vår webbplats.", + "CardDAV support is not yet available, follow this discussion on GitHub for updates": "CardDAV-stöd är ännu inte tillgängligt, följ denna diskussion på GitHub för uppdateringar", + "Please ensure that you have followed setup instructions for your domain.": "Se till att du har följt installationsinstruktionerna för din domän.", + "These instructions can be found in our FAQ section": "Dessa instruktioner finns i vår FAQ-sektion", + "Do you support receiving email with IMAP?": "Stöder du att ta emot e-post med IMAP?", + "This will": "Detta kommer", + "send an email – it will only simply add the message to your mailbox folder (e.g. this is similar to the IMAP": "skicka ett e-postmeddelande – det kommer bara att lägga till meddelandet i din brevlådemapp (t.ex. liknar det IMAP", + "command). If you would like to send an email, then see": "kommando). Om du vill skicka ett e-postmeddelande, se då", + "below. After creating the outbound SMTP email, then you can append a copy of it using this endpoint to your alias' mailbox for storage purposes.": "nedan. När du har skapat den utgående SMTP-e-posten kan du lägga till en kopia av den med denna slutpunkt till ditt alias brevlåda för lagringsändamål.", + "Folder endpoints with a folder's path": "Mappslutpunkter med en mapps sökväg", + "as their endpoint are interchangeable with a folder's ID": "eftersom deras slutpunkt är utbytbara med en mapps ID", + ". This means you can refer to the folder by either its": ". Detta innebär att du kan referera till mappen med antingen dess", + "These instructions can be found at": "Dessa instruktioner finns på", + "Note that this endpoint does not return property values for an email's": "Observera att denna slutpunkt inte returnerar egenskapsvärden för ett e-postmeddelande", + "Sort by a specific field (prefix with a single hyphen": "Sortera efter ett specifikt fält (prefix med ett enda bindestreck", + "to sort in the reverse direction of that field). Defaults to": "för att sortera i omvänd riktning av det fältet). Standard till", + "if not set.": "om inte inställt.", + "for more insight": "för mer insikt", + "as their endpoint are interchangeable with a domain's ID": "eftersom deras slutpunkt är utbytbara med en domäns ID", + "as an additional querystring parameter to the URL for the endpoint query. See": "som en extra frågesträngsparameter till URL:en för ändpunktsfrågan. Se", + "(\"SRS\") address here to protect against spoofing with our SRS domain name. We also check the recipient against our": "(\"SRS\") adress här för att skydda mot spoofing med vårt SRS-domännamn. Vi kontrollerar även mottagaren mot vår", + "- this is only applicable for outbound SMTP and correlates to the email ID stored in My Account → Emails": "- detta är endast tillämpligt för utgående SMTP och korrelerar med e-post-ID:t lagrat i Mitt konto → E-postmeddelanden", + "Bank Transfer": "Banköverföring", + "Domestic Wire Transfer (Enterprise)": "Inrikes banköverföring (företag)", + "International Wire Transfer (Enterprise)": "Internationell banköverföring (företag)" } \ No newline at end of file diff --git a/locales/th.json b/locales/th.json index 41047a293..ad1bb9515 100644 --- a/locales/th.json +++ b/locales/th.json @@ -10154,5 +10154,104 @@ "Reviews, comparison, screenshots and more for the 80 best email services.": "บทวิจารณ์ การเปรียบเทียบ ภาพหน้าจอ และอื่นๆ อีกมากมายสำหรับบริการอีเมลที่ดีที่สุด 80 อันดับ", "The Missing Email": "อีเมล์ที่หายไป", "14 Best Private Email Services in 2024": "บริการอีเมลส่วนตัวที่ดีที่สุด 14 อันดับใน 2024", - "Reviews, comparison, screenshots and more for the 14 best private email services.": "บทวิจารณ์ การเปรียบเทียบ ภาพหน้าจอ และอื่นๆ อีกมากมายสำหรับบริการอีเมลส่วนตัวที่ดีที่สุด 14 อันดับ" + "Reviews, comparison, screenshots and more for the 14 best private email services.": "บทวิจารณ์ การเปรียบเทียบ ภาพหน้าจอ และอื่นๆ อีกมากมายสำหรับบริการอีเมลส่วนตัวที่ดีที่สุด 14 อันดับ", + "Notice: API pagination required starting November 1st": "หมายเหตุ: จำเป็นต้องมีการแบ่งหน้า API ตั้งแต่วันที่ 1 พฤศจิกายนเป็นต้นไป", + "Starting November 1st of this year we will be enforcing API pagination on our API endpoints for list domains and list domain aliases. Learn more about our approach to API pagination and how you can opt-in beforehand at %s.": "เริ่มตั้งแต่วันที่ 1 พฤศจิกายนของปีนี้ เราจะบังคับใช้การแบ่งหน้า API บนจุดสิ้นสุด API ของเราสำหรับโดเมนรายการและนามแฝงโดเมนรายการ เรียนรู้เพิ่มเติมเกี่ยวกับแนวทางของเราในการแบ่งหน้า API และวิธีการสมัครใช้งานล่วงหน้าได้ที่ %s", + "Alias Contacts (CardDAV)": "รายชื่อผู้ติดต่อนามแฝง (CardDAV)", + "List contacts": "รายชื่อผู้ติดต่อ", + "Create contact": "สร้างการติดต่อ", + "Retrieve contact": "ดึงข้อมูลการติดต่อ", + "Update contact": "อัปเดตข้อมูลติดต่อ", + "Delete contact": "ลบข้อมูลติดต่อ", + "Alias Calendars (CalDAV)": "ปฏิทินนามแฝง (CalDAV)", + "List calendars": "รายการปฏิทิน", + "Create calendar": "สร้างปฏิทิน", + "Retrieve calendar": "ดึงข้อมูลปฏิทิน", + "Update calendar": "อัปเดตปฏิทิน", + "Delete calendar": "ลบปฏิทิน", + "Alias Messages (IMAP/POP3)": "ข้อความนามแฝง (IMAP/POP3)", + "List and search for messages": "รายการและค้นหาข้อความ", + "Create message": "สร้างข้อความ", + "Retrieve message": "ดึงข้อความ", + "Update message": "อัปเดตข้อความ", + "Delete message": "ลบข้อความ", + "Alias Folders (IMAP/POP3)": "โฟลเดอร์นามแฝง (IMAP/POP3)", + "List folders": "รายการโฟลเดอร์", + "Create folder": "สร้างโฟลเดอร์", + "Retrieve folder": "ดึงข้อมูลโฟลเดอร์", + "Update folder": "อัพเดตโฟลเดอร์", + "Delete folder": "ลบโฟลเดอร์", + "Copy folder": "คัดลอกโฟลเดอร์", + "Outbound Emails": "อีเมล์ขาออก", + "Get outbound SMTP email limit": "รับขีดจำกัดอีเมล SMTP ขาออก", + "List outbound SMTP emails": "รายชื่ออีเมล SMTP ขาออก", + "Create outbound SMTP email": "สร้างอีเมล SMTP ขาออก", + "Retrieve outbound SMTP email": "ดึงข้อมูลอีเมล SMTP ขาออก", + "Delete outbound SMTP email": "ลบอีเมล์ SMTP ขาออก", + "header (with the exception of": "ส่วนหัว (ยกเว้น", + "Alias Contacts": "นามแฝงที่ติดต่อ", + "Alias Calendars": "ปฏิทินนามแฝง", + "Alias Mailboxes": "กล่องจดหมายนามแฝง", + "which use a": "ซึ่งใช้", + "generated alias username and password": "สร้างชื่อผู้ใช้และรหัสผ่านนามแฝง", + "Don't worry – examples are provided below for you if you're not sure what this is.": "ไม่ต้องกังวล – มีตัวอย่างด้านล่างนี้ให้คุณหากคุณไม่แน่ใจว่านี่คืออะไร", + "As of November 1st, 2024 the API endpoints for": "ตั้งแต่วันที่ 1 พฤศจิกายน 2024 จุดสิ้นสุด API สำหรับ", + "will default to": "จะค่าเริ่มต้นเป็น", + "max results per page. If you would like to opt-in to this behavior early, you can pass": "ผลลัพธ์สูงสุดต่อหน้า หากคุณต้องการเลือกใช้พฤติกรรมนี้ก่อนกำหนด คุณสามารถผ่าน", + "as an additional querystring parameter to the URL for the endpoint query.": "เป็นพารามิเตอร์ querystring เพิ่มเติมให้กับ URL สำหรับการสอบถามจุดสิ้นสุด", + "Pagination is supported by all API endpoints that list results.": "รองรับการแบ่งหน้าโดยจุดสิ้นสุด API ทั้งหมดที่แสดงรายการผลลัพธ์", + "Simply provide the querystring properties": "เพียงให้คุณสมบัติของ querystring", + "(and optionally": "(และทางเลือก", + "The property": "ทรัพย์สิน", + "should be a number greater than or equal to": "ควรเป็นตัวเลขที่มากกว่าหรือเท่ากับ", + ". If you provide": ". หากคุณให้", + "(also a number), then the minimum value is": "(เป็นตัวเลขด้วย) ดังนั้นค่าต่ำสุดคือ", + "and maximum is": "และสูงสุดคือ", + "(unless otherwise noted).": "(เว้นแต่จะระบุไว้เป็นอย่างอื่น)", + "Page of results to return. If not specified, the": "หน้าผลลัพธ์ที่จะกลับคืนมา หากไม่ได้ระบุไว้", + "value will be": "ค่าจะเป็น", + ". Must be a number greater than or equal to": ". ต้องเป็นตัวเลขที่มากกว่าหรือเท่ากับ", + "Number of results to return per page. Defaults to": "จำนวนผลลัพธ์ที่จะแสดงต่อหน้า ค่าเริ่มต้นคือ", + "if not specified. Must be a number greater than or equal to": "หากไม่ได้ระบุไว้ จะต้องเป็นตัวเลขที่มากกว่าหรือเท่ากับ", + ", and less than or equal to": "และน้อยกว่าหรือเท่ากับ", + "In order to determine whether or not more results are available, we provide these HTTP response headers (which you can parse in order to paginate programmatically):": "เพื่อตรวจสอบว่ามีผลลัพธ์เพิ่มเติมหรือไม่ เราจึงจัดเตรียมส่วนหัวการตอบสนอง HTTP เหล่านี้ (ซึ่งคุณสามารถแยกวิเคราะห์เพื่อแบ่งหน้าตามโปรแกรมได้):", + "HTTP Response Header": "ส่วนหัวการตอบสนอง HTTP", + "The total page count available.": "จำนวนหน้ารวมที่มีอยู่", + "The current page of results returned (e.g. based off": "หน้าผลลัพธ์ปัจจุบันที่ส่งกลับมา (เช่น อ้างอิงจาก", + "querystring parameter).": "พารามิเตอร์สตริงการสืบค้น)", + "The total number of results in the page returned (e.g. based off": "จำนวนผลลัพธ์ทั้งหมดในเพจที่ส่งคืน (เช่น ขึ้นอยู่กับ", + "querystring parameter and actual results returned).": "พารามิเตอร์ querystring และผลลัพธ์จริงที่ส่งคืน)", + "The total number of items available across all pages.": "จำนวนรายการทั้งหมดที่มีอยู่ในทุกหน้า", + "We provide a": "เราจัดให้มี", + "HTTP response header you can parse as shown in the example. This is": "ส่วนหัวการตอบสนอง HTTP ที่คุณสามารถแยกวิเคราะห์ได้ตามที่แสดงในตัวอย่าง นี่คือ", + "similar to GitHub": "คล้ายกับ GitHub", + "(e.g. not all values will be provided if they are not relevant or available, e.g.": "(เช่น จะไม่มีการให้ค่าทั้งหมดหากค่าเหล่านั้นไม่เกี่ยวข้องหรือไม่สามารถใช้ได้ เช่น", + "will not be provided if there is not another page).": "หากไม่มีหน้าอื่นจะไม่ได้รับการให้บริการ)", + "Unlike other API endpoints, these require": "ต่างจากจุดสิ้นสุด API อื่น ๆ สิ่งเหล่านี้จำเป็นต้องใช้", + "\"username\" equal to the alias username and \"password\" equal to the alias generated password as Basic Authorization headers.": "“ชื่อผู้ใช้” จะเท่ากับชื่อผู้ใช้และ “รหัสผ่าน” จะเท่ากับรหัสผ่านที่สร้างขึ้นโดยใช้ชื่อแทนตามส่วนหัวการอนุญาตพื้นฐาน", + "This endpoint section is a work in progress and will be released (hopefully) in 2024. In the interim please use an IMAP client from the \"Apps\" dropdown in the navigation of our website.": "ส่วนปลายทางนี้ยังอยู่ระหว่างการดำเนินการ และจะเปิดตัว (หวังว่าจะเป็นเช่นนั้น) ในปี 2024 ในระหว่างนี้ โปรดใช้ไคลเอนต์ IMAP จากเมนูแบบดรอปดาวน์ \"แอป\" ในการนำทางของเว็บไซต์ของเรา", + "CardDAV support is not yet available, follow this discussion on GitHub for updates": "ยังไม่มีการรองรับ CardDAV โปรดติดตามการสนทนานี้บน GitHub เพื่อรับข้อมูลอัปเดต", + "Please ensure that you have followed setup instructions for your domain.": "โปรดตรวจสอบให้แน่ใจว่าคุณได้ปฏิบัติตามคำแนะนำในการตั้งค่าโดเมนของคุณแล้ว", + "These instructions can be found in our FAQ section": "คำแนะนำเหล่านี้สามารถพบได้ในส่วนคำถามที่พบบ่อยของเรา", + "Do you support receiving email with IMAP?": "คุณรองรับการรับอีเมล์ด้วย IMAP หรือไม่?", + "This will": "สิ่งนี้จะ", + "send an email – it will only simply add the message to your mailbox folder (e.g. this is similar to the IMAP": "ส่งอีเมล – เพียงแค่เพิ่มข้อความลงในโฟลเดอร์กล่องจดหมายของคุณ (เช่น คล้ายกับ IMAP)", + "command). If you would like to send an email, then see": "คำสั่ง) หากคุณต้องการส่งอีเมล์ โปรดดู", + "below. After creating the outbound SMTP email, then you can append a copy of it using this endpoint to your alias' mailbox for storage purposes.": "ด้านล่าง หลังจากสร้างอีเมล SMTP ขาออกแล้ว คุณสามารถผนวกสำเนาของอีเมลโดยใช้จุดสิ้นสุดนี้ไปยังกล่องจดหมายของนามแฝงของคุณเพื่อวัตถุประสงค์ในการจัดเก็บข้อมูล", + "Folder endpoints with a folder's path": "จุดสิ้นสุดของโฟลเดอร์พร้อมเส้นทางของโฟลเดอร์", + "as their endpoint are interchangeable with a folder's ID": "เนื่องจากจุดสิ้นสุดสามารถใช้แทน ID ของโฟลเดอร์ได้", + ". This means you can refer to the folder by either its": "ซึ่งหมายความว่าคุณสามารถอ้างอิงโฟลเดอร์ได้โดยใช้", + "These instructions can be found at": "คำแนะนำเหล่านี้สามารถพบได้ที่", + "Note that this endpoint does not return property values for an email's": "โปรดทราบว่าจุดสิ้นสุดนี้จะไม่ส่งคืนค่าคุณสมบัติสำหรับอีเมล", + "Sort by a specific field (prefix with a single hyphen": "เรียงลำดับตามฟิลด์ที่ระบุ (คำนำหน้าด้วยเครื่องหมายขีดกลางเพียงตัวเดียว", + "to sort in the reverse direction of that field). Defaults to": "เพื่อเรียงลำดับในทิศทางย้อนกลับของฟิลด์นั้น) ค่าเริ่มต้นคือ", + "if not set.": "หากไม่ได้ตั้งค่า", + "for more insight": "เพื่อความเข้าใจที่มากขึ้น", + "as their endpoint are interchangeable with a domain's ID": "เนื่องจากจุดสิ้นสุดสามารถใช้แทนกันได้กับ ID ของโดเมน", + "as an additional querystring parameter to the URL for the endpoint query. See": "เป็นพารามิเตอร์ querystring เพิ่มเติมสำหรับ URL สำหรับการสอบถามจุดสิ้นสุด ดู", + "(\"SRS\") address here to protect against spoofing with our SRS domain name. We also check the recipient against our": "(\"SRS\") ที่นี่เพื่อป้องกันการปลอมแปลงด้วยชื่อโดเมน SRS ของเรา นอกจากนี้ เรายังตรวจสอบผู้รับกับ", + "- this is only applicable for outbound SMTP and correlates to the email ID stored in My Account → Emails": "- ใช้ได้เฉพาะกับ SMTP ขาออกเท่านั้น และสัมพันธ์กับ ID อีเมลที่เก็บไว้ในบัญชีของฉัน → อีเมล", + "Bank Transfer": "โอนเงินผ่านธนาคาร", + "Domestic Wire Transfer (Enterprise)": "การโอนเงินภายในประเทศ (องค์กร)", + "International Wire Transfer (Enterprise)": "การโอนเงินระหว่างประเทศ (องค์กร)" } \ No newline at end of file diff --git a/locales/tr.json b/locales/tr.json index dba2f2a99..0005478a6 100644 --- a/locales/tr.json +++ b/locales/tr.json @@ -10154,5 +10154,104 @@ "Reviews, comparison, screenshots and more for the 80 best email services.": "En iyi 80 e-posta servisi için incelemeler, karşılaştırmalar, ekran görüntüleri ve daha fazlası.", "The Missing Email": "Kayıp E-posta", "14 Best Private Email Services in 2024": "2024 En İyi 14 Özel E-posta Hizmeti", - "Reviews, comparison, screenshots and more for the 14 best private email services.": "En iyi 14 özel e-posta servisi hakkında incelemeler, karşılaştırmalar, ekran görüntüleri ve daha fazlası." + "Reviews, comparison, screenshots and more for the 14 best private email services.": "En iyi 14 özel e-posta servisi hakkında incelemeler, karşılaştırmalar, ekran görüntüleri ve daha fazlası.", + "Notice: API pagination required starting November 1st": "Uyarı: 1 Kasım'dan itibaren API sayfalandırması zorunludur", + "Starting November 1st of this year we will be enforcing API pagination on our API endpoints for list domains and list domain aliases. Learn more about our approach to API pagination and how you can opt-in beforehand at %s.": "Bu yılın 1 Kasım'ından itibaren API uç noktalarımızda liste alan adları ve liste alan adı takma adları için API sayfalandırmasını zorunlu kılacağız. API sayfalandırmasına yaklaşımımız ve önceden nasıl katılabileceğiniz hakkında daha fazla bilgi edinmek için %s adresini ziyaret edin.", + "Alias Contacts (CardDAV)": "Takma Adlı Kişiler (CardDAV)", + "List contacts": "Kişileri listele", + "Create contact": "İletişim oluştur", + "Retrieve contact": "İletişimi al", + "Update contact": "İletişim bilgilerini güncelle", + "Delete contact": "Kişiyi sil", + "Alias Calendars (CalDAV)": "Takma Adlı Takvimler (CalDAV)", + "List calendars": "Takvimleri listele", + "Create calendar": "Takvim oluştur", + "Retrieve calendar": "Takvimi al", + "Update calendar": "Takvimi güncelle", + "Delete calendar": "Takvimi sil", + "Alias Messages (IMAP/POP3)": "Takma Adlı Mesajlar (IMAP/POP3)", + "List and search for messages": "Mesajları listele ve ara", + "Create message": "Mesaj oluştur", + "Retrieve message": "Mesajı al", + "Update message": "Mesajı güncelle", + "Delete message": "Mesajı sil", + "Alias Folders (IMAP/POP3)": "Takma Ad Klasörleri (IMAP/POP3)", + "List folders": "Klasörleri listele", + "Create folder": "Klasör oluştur", + "Retrieve folder": "Klasörü al", + "Update folder": "Klasörü güncelle", + "Delete folder": "Klasörü sil", + "Copy folder": "Klasörü kopyala", + "Outbound Emails": "Giden E-postalar", + "Get outbound SMTP email limit": "Giden SMTP e-posta limitini al", + "List outbound SMTP emails": "Giden SMTP e-postalarını listele", + "Create outbound SMTP email": "Giden SMTP e-postası oluştur", + "Retrieve outbound SMTP email": "Giden SMTP e-postasını al", + "Delete outbound SMTP email": "Giden SMTP e-postasını sil", + "header (with the exception of": "başlık (istisnalar hariç)", + "Alias Contacts": "Takma Adlı Kişiler", + "Alias Calendars": "Takma Adlı Takvimler", + "Alias Mailboxes": "Takma Adlı Posta Kutuları", + "which use a": "hangisini kullanır", + "generated alias username and password": "oluşturulan takma ad kullanıcı adı ve şifre", + "Don't worry – examples are provided below for you if you're not sure what this is.": "Endişelenmeyin, eğer bunun ne olduğunu bilmiyorsanız, aşağıda sizin için örnekler verilmiştir.", + "As of November 1st, 2024 the API endpoints for": "1 Kasım 2024 itibarıyla API uç noktaları", + "will default to": "varsayılan olarak", + "max results per page. If you would like to opt-in to this behavior early, you can pass": "sayfa başına maksimum sonuç. Bu davranışı erken kabul etmek isterseniz, geçebilirsiniz", + "as an additional querystring parameter to the URL for the endpoint query.": "uç nokta sorgusu için URL'ye ek bir sorgu dizesi parametresi olarak.", + "Pagination is supported by all API endpoints that list results.": "Sayfalandırma, sonuçları listeleyen tüm API uç noktaları tarafından desteklenir.", + "Simply provide the querystring properties": "Sadece sorgu dizesi özelliklerini sağlayın", + "(and optionally": "(ve isteğe bağlı olarak", + "The property": "Mülkiyet", + "should be a number greater than or equal to": "büyük veya eşit bir sayı olmalıdır", + ". If you provide": "Eğer sağlarsanız", + "(also a number), then the minimum value is": "(aynı zamanda bir sayı), o zaman minimum değer şudur:", + "and maximum is": "ve maksimum", + "(unless otherwise noted).": "(aksi belirtilmediği takdirde).", + "Page of results to return. If not specified, the": "Döndürülecek sonuç sayfası. Belirtilmezse,", + "value will be": "değer olacak", + ". Must be a number greater than or equal to": ". 'den büyük veya eşit bir sayı olmalıdır", + "Number of results to return per page. Defaults to": "Sayfa başına döndürülecek sonuç sayısı. Varsayılan değer:", + "if not specified. Must be a number greater than or equal to": "belirtilmemişse. 'den büyük veya eşit bir sayı olmalıdır", + ", and less than or equal to": "ve küçük veya eşit", + "In order to determine whether or not more results are available, we provide these HTTP response headers (which you can parse in order to paginate programmatically):": "Daha fazla sonucun mevcut olup olmadığını belirlemek için, şu HTTP yanıt başlıklarını sağlıyoruz (bunları programatik olarak sayfalandırmak için ayrıştırabilirsiniz):", + "HTTP Response Header": "HTTP Yanıt Başlığı", + "The total page count available.": "Toplam mevcut sayfa sayısı.", + "The current page of results returned (e.g. based off": "Döndürülen sonuçların geçerli sayfası (örneğin, aşağıdakilere göre)", + "querystring parameter).": "sorgu dizesi parametreleri).", + "The total number of results in the page returned (e.g. based off": "Sayfada döndürülen toplam sonuç sayısı (örneğin,", + "querystring parameter and actual results returned).": "sorgu dizesi parametresi ve döndürülen gerçek sonuçlar).", + "The total number of items available across all pages.": "Tüm sayfalarda mevcut toplam öğe sayısı.", + "We provide a": "Biz bir", + "HTTP response header you can parse as shown in the example. This is": "Örnekte gösterildiği gibi ayrıştırabileceğiniz HTTP yanıt başlığı. Bu", + "similar to GitHub": "GitHub'a benzer", + "(e.g. not all values will be provided if they are not relevant or available, e.g.": "(örneğin, ilgili veya mevcut değilse tüm değerler sağlanmayacaktır, örneğin", + "will not be provided if there is not another page).": "(Başka bir sayfa yoksa verilmeyecektir).", + "Unlike other API endpoints, these require": "Diğer API uç noktalarından farklı olarak, bunlar şunları gerektirir:", + "\"username\" equal to the alias username and \"password\" equal to the alias generated password as Basic Authorization headers.": "Temel Yetkilendirme başlıkları olarak \"kullanıcı adı\" takma ad kullanıcı adına, \"şifre\" ise takma ad tarafından oluşturulan parolaya eşittir.", + "This endpoint section is a work in progress and will be released (hopefully) in 2024. In the interim please use an IMAP client from the \"Apps\" dropdown in the navigation of our website.": "Bu uç nokta bölümü devam eden bir çalışmadır ve (umarız) 2024'te yayınlanacaktır. Bu arada lütfen web sitemizin gezinme bölümündeki \"Uygulamalar\" açılır menüsünden bir IMAP istemcisi kullanın.", + "CardDAV support is not yet available, follow this discussion on GitHub for updates": "CardDAV desteği henüz mevcut değil, güncellemeler için GitHub'daki bu tartışmayı takip edin", + "Please ensure that you have followed setup instructions for your domain.": "Lütfen alan adınız için kurulum talimatlarını izlediğinizden emin olun.", + "These instructions can be found in our FAQ section": "Bu talimatlar SSS bölümümüzde bulunabilir", + "Do you support receiving email with IMAP?": "E-postaların IMAP ile alınmasını destekliyor musunuz?", + "This will": "Bu olacak", + "send an email – it will only simply add the message to your mailbox folder (e.g. this is similar to the IMAP": "bir e-posta gönderin – bu yalnızca mesajı posta kutusu klasörünüze ekleyecektir (örneğin bu IMAP'e benzer)", + "command). If you would like to send an email, then see": "(komut). E-posta göndermek isterseniz, bkz.", + "below. After creating the outbound SMTP email, then you can append a copy of it using this endpoint to your alias' mailbox for storage purposes.": "Aşağıda. Giden SMTP e-postasını oluşturduktan sonra, bu uç noktayı kullanarak bir kopyasını depolama amacıyla takma adınızın posta kutusuna ekleyebilirsiniz.", + "Folder endpoints with a folder's path": "Klasörün yoluna sahip klasör uç noktaları", + "as their endpoint are interchangeable with a folder's ID": "uç noktaları bir klasörün kimliğiyle değiştirilebilir olduğundan", + ". This means you can refer to the folder by either its": "Bu, klasöre şu şekilde başvurabileceğiniz anlamına gelir:", + "These instructions can be found at": "Bu talimatlar şu adreste bulunabilir:", + "Note that this endpoint does not return property values for an email's": "Bu uç noktanın bir e-postanın özellik değerlerini döndürmediğini unutmayın", + "Sort by a specific field (prefix with a single hyphen": "Belirli bir alana göre sırala (tek tireli önek)", + "to sort in the reverse direction of that field). Defaults to": "(Bu alanın ters yönünde sıralamak için). Varsayılan olarak", + "if not set.": "ayarlanmamışsa.", + "for more insight": "daha fazla bilgi için", + "as their endpoint are interchangeable with a domain's ID": "uç noktaları bir alan adının kimliğiyle değiştirilebilir olduğundan", + "as an additional querystring parameter to the URL for the endpoint query. See": "uç nokta sorgusu için URL'ye ek bir sorgu dizesi parametresi olarak. Bkz.", + "(\"SRS\") address here to protect against spoofing with our SRS domain name. We also check the recipient against our": "(\"SRS\") adresimizi SRS alan adımızla sahteciliğe karşı korumak için buraya yazıyoruz. Ayrıca alıcıyı", + "- this is only applicable for outbound SMTP and correlates to the email ID stored in My Account → Emails": "- bu yalnızca giden SMTP için geçerlidir ve Hesabım → E-postalar'da saklanan e-posta kimliğiyle ilişkilidir", + "Bank Transfer": "Banka Havalesi", + "Domestic Wire Transfer (Enterprise)": "Yurtiçi Havale (Kurumsal)", + "International Wire Transfer (Enterprise)": "Uluslararası Havale (Kurumsal)" } \ No newline at end of file diff --git a/locales/uk.json b/locales/uk.json index c8660ee12..b0645a28a 100644 --- a/locales/uk.json +++ b/locales/uk.json @@ -10154,5 +10154,104 @@ "Reviews, comparison, screenshots and more for the 80 best email services.": "Огляди, порівняння, знімки екрана та інше для 80 найкращих служб електронної пошти.", "The Missing Email": "Відсутня електронна адреса", "14 Best Private Email Services in 2024": "14 найкращих служб приватної електронної пошти у 2024", - "Reviews, comparison, screenshots and more for the 14 best private email services.": "Огляди, порівняння, знімки екрана та багато іншого для 14 найкращих служб приватної електронної пошти." + "Reviews, comparison, screenshots and more for the 14 best private email services.": "Огляди, порівняння, знімки екрана та багато іншого для 14 найкращих служб приватної електронної пошти.", + "Notice: API pagination required starting November 1st": "Примітка: з 1 листопада потрібна пагінація API", + "Starting November 1st of this year we will be enforcing API pagination on our API endpoints for list domains and list domain aliases. Learn more about our approach to API pagination and how you can opt-in beforehand at %s.": "Починаючи з 1 листопада цього року, ми запровадимо розбивку сторінок API на наших кінцевих точках API для доменів списків і псевдонімів доменів. Дізнайтеся більше про наш підхід до розбивки сторінок API та про те, як ви можете заздалегідь увімкнутись, на %s .", + "Alias Contacts (CardDAV)": "Псевдонім контактів (CardDAV)", + "List contacts": "Список контактів", + "Create contact": "Створити контакт", + "Retrieve contact": "Отримати контакт", + "Update contact": "Оновити контакт", + "Delete contact": "Видалити контакт", + "Alias Calendars (CalDAV)": "Календарі псевдонімів (CalDAV)", + "List calendars": "Список календарів", + "Create calendar": "Створити календар", + "Retrieve calendar": "Отримати календар", + "Update calendar": "Оновлення календаря", + "Delete calendar": "Видалити календар", + "Alias Messages (IMAP/POP3)": "Повідомлення псевдонімів (IMAP/POP3)", + "List and search for messages": "Список і пошук повідомлень", + "Create message": "Створити повідомлення", + "Retrieve message": "Отримати повідомлення", + "Update message": "Оновити повідомлення", + "Delete message": "Видалити повідомлення", + "Alias Folders (IMAP/POP3)": "Псевдоніми папок (IMAP/POP3)", + "List folders": "Список папок", + "Create folder": "Створити папку", + "Retrieve folder": "Отримати папку", + "Update folder": "Оновити папку", + "Delete folder": "Видалити папку", + "Copy folder": "Копіювати папку", + "Outbound Emails": "Вихідні електронні листи", + "Get outbound SMTP email limit": "Отримайте ліміт вихідної електронної пошти SMTP", + "List outbound SMTP emails": "Список вихідних електронних листів SMTP", + "Create outbound SMTP email": "Створення вихідної електронної пошти SMTP", + "Retrieve outbound SMTP email": "Отримати вихідну електронну пошту SMTP", + "Delete outbound SMTP email": "Видалити вихідну електронну пошту SMTP", + "header (with the exception of": "заголовок (за винятком", + "Alias Contacts": "Псевдонім Контакти", + "Alias Calendars": "Календарі псевдонімів", + "Alias Mailboxes": "Псевдоніми поштових скриньок", + "which use a": "які використовують a", + "generated alias username and password": "створений псевдонім імені користувача та пароля", + "Don't worry – examples are provided below for you if you're not sure what this is.": "Не хвилюйтеся – нижче наведено приклади, якщо ви не впевнені, що це таке.", + "As of November 1st, 2024 the API endpoints for": "Станом на 1 листопада 2024 року кінцеві точки API для", + "will default to": "за замовчуванням", + "max results per page. If you would like to opt-in to this behavior early, you can pass": "максимальна кількість результатів на сторінку. Якщо ви хочете раніше погодитися на таку поведінку, ви можете пройти", + "as an additional querystring parameter to the URL for the endpoint query.": "як додатковий параметр рядка запиту до URL-адреси для запиту кінцевої точки.", + "Pagination is supported by all API endpoints that list results.": "Розбивка на сторінки підтримується всіма кінцевими точками API, які перераховують результати.", + "Simply provide the querystring properties": "Просто введіть властивості рядка запиту", + "(and optionally": "(і за бажанням", + "The property": "Власність", + "should be a number greater than or equal to": "має бути числом, більшим або рівним", + ". If you provide": ". Якщо ви надаєте", + "(also a number), then the minimum value is": "(також число), то мінімальне значення дорівнює", + "and maximum is": "і максимум є", + "(unless otherwise noted).": "(якщо не зазначено інше).", + "Page of results to return. If not specified, the": "Сторінка результатів для повернення. Якщо не зазначено, то", + "value will be": "значення буде", + ". Must be a number greater than or equal to": ". Має бути число більше або дорівнює", + "Number of results to return per page. Defaults to": "Кількість результатів для повернення на сторінку. За замовчуванням", + "if not specified. Must be a number greater than or equal to": "якщо не зазначено. Має бути число більше або дорівнює", + ", and less than or equal to": ", і менше або дорівнює", + "In order to determine whether or not more results are available, we provide these HTTP response headers (which you can parse in order to paginate programmatically):": "Щоб визначити, чи доступні інші результати, ми надаємо ці заголовки HTTP-відповідей (які можна проаналізувати, щоб розбити на сторінки програмно):", + "HTTP Response Header": "Заголовок відповіді HTTP", + "The total page count available.": "Загальна доступна кількість сторінок.", + "The current page of results returned (e.g. based off": "Повернута поточна сторінка результатів (наприклад, на основі", + "querystring parameter).": "параметри рядка запиту).", + "The total number of results in the page returned (e.g. based off": "Загальна кількість отриманих результатів на сторінці (наприклад, на основі", + "querystring parameter and actual results returned).": "параметр рядка запиту та повернуті фактичні результати).", + "The total number of items available across all pages.": "Загальна кількість елементів, доступних на всіх сторінках.", + "We provide a": "Ми надаємо a", + "HTTP response header you can parse as shown in the example. This is": "Заголовок відповіді HTTP можна проаналізувати, як показано в прикладі. Це є", + "similar to GitHub": "схожий на GitHub", + "(e.g. not all values will be provided if they are not relevant or available, e.g.": "(наприклад, не всі значення будуть надані, якщо вони нерелевантні або доступні, напр.", + "will not be provided if there is not another page).": "не буде надано, якщо немає іншої сторінки).", + "Unlike other API endpoints, these require": "На відміну від інших кінцевих точок API, ці вимагають", + "\"username\" equal to the alias username and \"password\" equal to the alias generated password as Basic Authorization headers.": "\"username\" дорівнює псевдоніму імені користувача та \"password\" дорівнює псевдоніму згенерованого пароля як заголовки базової авторизації.", + "This endpoint section is a work in progress and will be released (hopefully) in 2024. In the interim please use an IMAP client from the \"Apps\" dropdown in the navigation of our website.": "Цей розділ кінцевої точки ще триває і буде випущений (сподіваємось) у 2024 році. Тим часом використовуйте клієнт IMAP зі спадного меню «Програми» в навігаційній панелі нашого веб-сайту.", + "CardDAV support is not yet available, follow this discussion on GitHub for updates": "Підтримка CardDAV ще не доступна, слідкуйте за цією дискусією на GitHub, щоб отримати оновлення", + "Please ensure that you have followed setup instructions for your domain.": "Будь ласка, переконайтеся, що ви виконали інструкції з налаштування для свого домену.", + "These instructions can be found in our FAQ section": "Ці інструкції можна знайти в нашому розділі поширених запитань", + "Do you support receiving email with IMAP?": "Чи підтримуєте ви отримання електронної пошти через IMAP?", + "This will": "Це буде", + "send an email – it will only simply add the message to your mailbox folder (e.g. this is similar to the IMAP": "надіслати електронний лист – це лише додасть повідомлення до папки вашої поштової скриньки (наприклад, це схоже на IMAP", + "command). If you would like to send an email, then see": "команда). Якщо ви хочете надіслати електронний лист, див", + "below. After creating the outbound SMTP email, then you can append a copy of it using this endpoint to your alias' mailbox for storage purposes.": "нижче. Після створення вихідної електронної пошти SMTP ви можете додати її копію за допомогою цієї кінцевої точки до поштової скриньки псевдоніма для зберігання.", + "Folder endpoints with a folder's path": "Кінцеві точки папок із шляхом до папки", + "as their endpoint are interchangeable with a folder's ID": "оскільки їхня кінцева точка взаємозамінна з ідентифікатором папки", + ". This means you can refer to the folder by either its": ". Це означає, що ви можете звертатися до папки за допомогою її", + "These instructions can be found at": "Ці інструкції можна знайти за адресою", + "Note that this endpoint does not return property values for an email's": "Зауважте, що ця кінцева точка не повертає значення властивостей для електронних листів", + "Sort by a specific field (prefix with a single hyphen": "Сортувати за певним полем (префікс з одним дефісом", + "to sort in the reverse direction of that field). Defaults to": "для сортування у зворотному напрямку цього поля). За замовчуванням", + "if not set.": "якщо не встановлено.", + "for more insight": "для більшого розуміння", + "as their endpoint are interchangeable with a domain's ID": "оскільки їхня кінцева точка взаємозамінна з ідентифікатором домену", + "as an additional querystring parameter to the URL for the endpoint query. See": "як додатковий параметр рядка запиту до URL-адреси для запиту кінцевої точки. див", + "(\"SRS\") address here to protect against spoofing with our SRS domain name. We also check the recipient against our": "(\"SRS\") адресуйте тут, щоб захистити від підробки за допомогою нашого доменного імені SRS. Ми також звіряємо одержувача з нашим", + "- this is only applicable for outbound SMTP and correlates to the email ID stored in My Account → Emails": "- це стосується лише вихідного SMTP і співвідноситься з ідентифікатором електронної пошти, який зберігається в розділі «Мій обліковий запис» → «Електронні листи».", + "Bank Transfer": "Банківський переказ", + "Domestic Wire Transfer (Enterprise)": "Внутрішній банківський переказ (підприємство)", + "International Wire Transfer (Enterprise)": "Міжнародний банківський переказ (підприємство)" } \ No newline at end of file diff --git a/locales/vi.json b/locales/vi.json index 75ff4ab63..f8cd27dc4 100644 --- a/locales/vi.json +++ b/locales/vi.json @@ -7681,5 +7681,105 @@ "Reviews, comparison, screenshots and more for the 80 best email services.": "Đánh giá, so sánh, ảnh chụp màn hình và nhiều thông tin khác về 80 dịch vụ email tốt nhất.", "The Missing Email": "Email bị mất", "14 Best Private Email Services in 2024": "14 Dịch vụ Email Riêng tư Tốt nhất 2024", - "Reviews, comparison, screenshots and more for the 14 best private email services.": "Đánh giá, so sánh, ảnh chụp màn hình và nhiều thông tin khác về 14 dịch vụ email riêng tư tốt nhất." + "Reviews, comparison, screenshots and more for the 14 best private email services.": "Đánh giá, so sánh, ảnh chụp màn hình và nhiều thông tin khác về 14 dịch vụ email riêng tư tốt nhất.", + "Notice: API pagination required starting November 1st": "Lưu ý: Phân trang API bắt buộc bắt đầu từ ngày 1 tháng 11", + "Starting November 1st of this year we will be enforcing API pagination on our API endpoints for list domains and list domain aliases. Learn more about our approach to API pagination and how you can opt-in beforehand at %s.": "Bắt đầu từ ngày 1 tháng 11 năm nay, chúng tôi sẽ thực thi phân trang API trên các điểm cuối API của mình cho các miền danh sách và các bí danh miền danh sách. Tìm hiểu thêm về cách tiếp cận của chúng tôi đối với phân trang API và cách bạn có thể chọn tham gia trước tại %s .", + "Alias Contacts (CardDAV)": "Liên hệ bí danh (CardDAV)", + "List contacts": "Liệt kê danh bạ", + "Create contact": "Tạo liên hệ", + "Retrieve contact": "Lấy lại liên lạc", + "Update contact": "Cập nhật liên hệ", + "Delete contact": "Xóa liên lạc", + "Alias Calendars (CalDAV)": "Lịch bí danh (CalDAV)", + "List calendars": "Danh sách lịch", + "Create calendar": "Tạo lịch", + "Retrieve calendar": "Lấy lại lịch", + "Update calendar": "Cập nhật lịch", + "Delete calendar": "Xóa lịch", + "Alias Messages (IMAP/POP3)": "Tin nhắn bí danh (IMAP/POP3)", + "List and search for messages": "Liệt kê và tìm kiếm tin nhắn", + "Create message": "Tạo tin nhắn", + "Retrieve message": "Lấy lại tin nhắn", + "Update message": "Cập nhật tin nhắn", + "Delete message": "Xóa tin nhắn", + "Alias Folders (IMAP/POP3)": "Thư mục bí danh (IMAP/POP3)", + "List folders": "Danh sách thư mục", + "Create folder": "Tạo thư mục", + "Retrieve folder": "Lấy lại thư mục", + "Update folder": "Cập nhật thư mục", + "Delete folder": "Xóa thư mục", + "Copy folder": "Sao chép thư mục", + "Outbound Emails": "Email gửi đi", + "Get outbound SMTP email limit": "Nhận giới hạn email SMTP gửi đi", + "List outbound SMTP emails": "Liệt kê các email SMTP gửi đi", + "Create outbound SMTP email": "Tạo email SMTP gửi đi", + "Retrieve outbound SMTP email": "Lấy email SMTP gửi đi", + "Delete outbound SMTP email": "Xóa email SMTP gửi đi", + "header (with the exception of": "tiêu đề (ngoại trừ", + "Alias Contacts": "Liên hệ bí danh", + "Alias Calendars": "Lịch bí danh", + "Alias Mailboxes": "Hộp thư bí danh", + "which use a": "mà sử dụng một", + "generated alias username and password": "tạo tên người dùng và mật khẩu bí danh", + "Don't worry – examples are provided below for you if you're not sure what this is.": "Đừng lo lắng – các ví dụ được cung cấp bên dưới nếu bạn không chắc đây là gì.", + "As of November 1st, 2024 the API endpoints for": "Tính đến ngày 1 tháng 11 năm 2024, các điểm cuối API cho", + "will default to": "sẽ mặc định là", + "max results per page. If you would like to opt-in to this behavior early, you can pass": "kết quả tối đa trên mỗi trang. Nếu bạn muốn chọn tham gia hành vi này sớm, bạn có thể chuyển", + "as an additional querystring parameter to the URL for the endpoint query.": "như một tham số chuỗi truy vấn bổ sung cho URL cho truy vấn điểm cuối.", + "Pagination is supported by all API endpoints that list results.": "Phân trang được hỗ trợ bởi tất cả các điểm cuối API liệt kê kết quả.", + "Simply provide the querystring properties": "Chỉ cần cung cấp các thuộc tính chuỗi truy vấn", + "(and optionally": "(và tùy chọn", + "The property": "Tài sản", + "should be a number greater than or equal to": "phải là một số lớn hơn hoặc bằng", + ". If you provide": ". Nếu bạn cung cấp", + "(also a number), then the minimum value is": "(cũng là một số), thì giá trị nhỏ nhất là", + "and maximum is": "và tối đa là", + "(unless otherwise noted).": "(trừ khi có ghi chú khác).", + "Page of results to return. If not specified, the": "Trang kết quả để trả về. Nếu không được chỉ định,", + "value will be": "giá trị sẽ là", + ". Must be a number greater than or equal to": ". Phải là một số lớn hơn hoặc bằng", + "Number of results to return per page. Defaults to": "Số lượng kết quả trả về trên mỗi trang. Mặc định là", + "if not specified. Must be a number greater than or equal to": "nếu không được chỉ định. Phải là một số lớn hơn hoặc bằng", + ", and less than or equal to": "và nhỏ hơn hoặc bằng", + "In order to determine whether or not more results are available, we provide these HTTP response headers (which you can parse in order to paginate programmatically):": "Để xác định có thêm kết quả hay không, chúng tôi cung cấp các tiêu đề phản hồi HTTP sau (bạn có thể phân tích cú pháp để phân trang theo chương trình):", + "HTTP Response Header": "Tiêu đề phản hồi HTTP", + "The total page count available.": "Tổng số trang có sẵn.", + "The current page of results returned (e.g. based off": "Trang kết quả hiện tại được trả về (ví dụ: dựa trên", + "querystring parameter).": "tham số chuỗi truy vấn).", + "The total number of results in the page returned (e.g. based off": "Tổng số kết quả trong trang được trả về (ví dụ: dựa trên", + "querystring parameter and actual results returned).": "tham số chuỗi truy vấn và kết quả thực tế được trả về).", + "The total number of items available across all pages.": "Tổng số mục có sẵn trên tất cả các trang.", + "We provide a": "Chúng tôi cung cấp một", + "HTTP response header you can parse as shown in the example. This is": "Tiêu đề phản hồi HTTP bạn có thể phân tích như được hiển thị trong ví dụ. Đây là", + "similar to GitHub": "tương tự như GitHub", + "(e.g. not all values will be provided if they are not relevant or available, e.g.": "(ví dụ: không phải tất cả các giá trị sẽ được cung cấp nếu chúng không liên quan hoặc không khả dụng, ví dụ:", + "will not be provided if there is not another page).": "sẽ không được cung cấp nếu không có trang khác).", + "Unlike other API endpoints, these require": "Không giống như các điểm cuối API khác, những điểm cuối này yêu cầu", + "\"username\" equal to the alias username and \"password\" equal to the alias generated password as Basic Authorization headers.": "\"username\" bằng với tên người dùng bí danh và \"password\" bằng với mật khẩu được tạo bí danh làm tiêu đề Ủy quyền cơ bản.", + "This endpoint section is a work in progress and will be released (hopefully) in 2024. In the interim please use an IMAP client from the \"Apps\" dropdown in the navigation of our website.": "Phần điểm cuối này đang trong quá trình hoàn thiện và hy vọng sẽ được phát hành vào năm 2024. Trong thời gian chờ đợi, vui lòng sử dụng ứng dụng khách IMAP từ menu thả xuống \"Ứng dụng\" trong phần điều hướng của trang web của chúng tôi.", + "CardDAV support is not yet available, follow this discussion on GitHub for updates": "Hỗ trợ CardDAV hiện chưa khả dụng, hãy theo dõi cuộc thảo luận này trên GitHub để biết thông tin cập nhật", + "Coming soon": "Sắp ra mắt", + "Please ensure that you have followed setup instructions for your domain.": "Hãy đảm bảo rằng bạn đã làm theo hướng dẫn thiết lập cho tên miền của mình.", + "These instructions can be found in our FAQ section": "Những hướng dẫn này có thể được tìm thấy trong phần Câu hỏi thường gặp của chúng tôi", + "Do you support receiving email with IMAP?": "Bạn có hỗ trợ nhận email bằng IMAP không?", + "This will": "Điều này sẽ", + "send an email – it will only simply add the message to your mailbox folder (e.g. this is similar to the IMAP": "gửi email – nó chỉ đơn giản là thêm tin nhắn vào thư mục hộp thư của bạn (ví dụ: điều này tương tự như IMAP", + "command). If you would like to send an email, then see": "lệnh). Nếu bạn muốn gửi email, hãy xem", + "below. After creating the outbound SMTP email, then you can append a copy of it using this endpoint to your alias' mailbox for storage purposes.": "bên dưới. Sau khi tạo email SMTP gửi đi, bạn có thể thêm một bản sao của email đó bằng điểm cuối này vào hộp thư bí danh của mình để lưu trữ.", + "Folder endpoints with a folder's path": "Điểm cuối của thư mục với đường dẫn của thư mục", + "as their endpoint are interchangeable with a folder's ID": "vì điểm cuối của chúng có thể hoán đổi với ID của thư mục", + ". This means you can refer to the folder by either its": ". Điều này có nghĩa là bạn có thể tham chiếu đến thư mục bằng cách", + "These instructions can be found at": "Những hướng dẫn này có thể được tìm thấy tại", + "Note that this endpoint does not return property values for an email's": "Lưu ý rằng điểm cuối này không trả về giá trị thuộc tính cho email", + "Sort by a specific field (prefix with a single hyphen": "Sắp xếp theo một trường cụ thể (tiền tố có dấu gạch nối đơn", + "to sort in the reverse direction of that field). Defaults to": "để sắp xếp theo hướng ngược lại của trường đó). Mặc định là", + "if not set.": "nếu không được thiết lập.", + "for more insight": "để có thêm hiểu biết sâu sắc", + "as their endpoint are interchangeable with a domain's ID": "vì điểm cuối của chúng có thể hoán đổi với ID của miền", + "as an additional querystring parameter to the URL for the endpoint query. See": "như một tham số chuỗi truy vấn bổ sung cho URL cho truy vấn điểm cuối. Xem", + "(\"SRS\") address here to protect against spoofing with our SRS domain name. We also check the recipient against our": "(\"SRS\") địa chỉ ở đây để bảo vệ chống lại việc giả mạo với tên miền SRS của chúng tôi. Chúng tôi cũng kiểm tra người nhận với", + "- this is only applicable for outbound SMTP and correlates to the email ID stored in My Account → Emails": "- điều này chỉ áp dụng cho SMTP gửi đi và tương quan với ID email được lưu trữ trong Tài khoản của tôi → Email", + "Bank Transfer": "Chuyển khoản ngân hàng", + "Domestic Wire Transfer (Enterprise)": "Chuyển khoản trong nước (Doanh nghiệp)", + "International Wire Transfer (Enterprise)": "Chuyển khoản quốc tế (Doanh nghiệp)" } \ No newline at end of file diff --git a/locales/zh.json b/locales/zh.json index 5dc29deb9..2ceed2ef9 100644 --- a/locales/zh.json +++ b/locales/zh.json @@ -9847,5 +9847,104 @@ "Reviews, comparison, screenshots and more for the 80 best email services.": "80 种最佳电子邮件服务的评论、比较、屏幕截图等。", "The Missing Email": "丢失的电子邮件", "14 Best Private Email Services in 2024": "2024 14 款最佳私人电子邮件服务", - "Reviews, comparison, screenshots and more for the 14 best private email services.": "14 款最佳私人电子邮件服务的评论、比较、截图等。" + "Reviews, comparison, screenshots and more for the 14 best private email services.": "14 款最佳私人电子邮件服务的评论、比较、截图等。", + "Notice: API pagination required starting November 1st": "注意:11 月 1 日起需要 API 分页", + "Starting November 1st of this year we will be enforcing API pagination on our API endpoints for list domains and list domain aliases. Learn more about our approach to API pagination and how you can opt-in beforehand at %s.": "从今年 11 月 1 日开始,我们将在列表域和列表域别名的 API 端点上强制实施 API 分页。详细了解我们的 API 分页方法以及如何提前选择加入%s 。", + "Alias Contacts (CardDAV)": "别名联系人 (CardDAV)", + "List contacts": "列出联系人", + "Create contact": "创建联系人", + "Retrieve contact": "检索联系人", + "Update contact": "更新联系方式", + "Delete contact": "删除联系人", + "Alias Calendars (CalDAV)": "别名日历 (CalDAV)", + "List calendars": "列出日历", + "Create calendar": "创建日历", + "Retrieve calendar": "检索日历", + "Update calendar": "更新日历", + "Delete calendar": "删除日历", + "Alias Messages (IMAP/POP3)": "别名邮件 (IMAP/POP3)", + "List and search for messages": "列出并搜索消息", + "Create message": "创建消息", + "Retrieve message": "检索消息", + "Update message": "更新消息", + "Delete message": "删除消息", + "Alias Folders (IMAP/POP3)": "别名文件夹 (IMAP/POP3)", + "List folders": "列出文件夹", + "Create folder": "创建文件夹", + "Retrieve folder": "检索文件夹", + "Update folder": "更新文件夹", + "Delete folder": "删除文件夹", + "Copy folder": "复制文件夹", + "Outbound Emails": "外发电子邮件", + "Get outbound SMTP email limit": "获取出站 SMTP 电子邮件限制", + "List outbound SMTP emails": "列出出站 SMTP 电子邮件", + "Create outbound SMTP email": "创建出站 SMTP 电子邮件", + "Retrieve outbound SMTP email": "检索出站 SMTP 电子邮件", + "Delete outbound SMTP email": "删除出站 SMTP 电子邮件", + "header (with the exception of": "标题(除了", + "Alias Contacts": "别名联系人", + "Alias Calendars": "别名日历", + "Alias Mailboxes": "别名信箱", + "which use a": "使用", + "generated alias username and password": "生成的别名用户名和密码", + "Don't worry – examples are provided below for you if you're not sure what this is.": "别担心——如果您不确定这是什么,下面会为您提供示例。", + "As of November 1st, 2024 the API endpoints for": "自 2024 年 11 月 1 日起,API 端点", + "will default to": "将默认为", + "max results per page. If you would like to opt-in to this behavior early, you can pass": "每页最多结果数。如果您想尽早选择此行为,您可以通过", + "as an additional querystring parameter to the URL for the endpoint query.": "作为端点查询 URL 的附加查询字符串参数。", + "Pagination is supported by all API endpoints that list results.": "所有列出结果的 API 端点都支持分页。", + "Simply provide the querystring properties": "只需提供查询字符串属性", + "(and optionally": "(以及可选的", + "The property": "该物业", + "should be a number greater than or equal to": "应为大于或等于的数字", + ". If you provide": ".如果您提供", + "(also a number), then the minimum value is": "(也是一个数字),那么最小值是", + "and maximum is": "最大值为", + "(unless otherwise noted).": "(除非另有说明)。", + "Page of results to return. If not specified, the": "返回结果页。如果没有指定,则", + "value will be": "价值将", + ". Must be a number greater than or equal to": "。必须是大于或等于的数字", + "Number of results to return per page. Defaults to": "每页返回的结果数。默认为", + "if not specified. Must be a number greater than or equal to": "如果没有指定。必须是大于或等于的数字", + ", and less than or equal to": "并且小于或等于", + "In order to determine whether or not more results are available, we provide these HTTP response headers (which you can parse in order to paginate programmatically):": "为了确定是否有更多结果可用,我们提供了这些 HTTP 响应标头(您可以解析它们以便以编程方式进行分页):", + "HTTP Response Header": "HTTP 响应标头", + "The total page count available.": "可用的总页数。", + "The current page of results returned (e.g. based off": "返回的当前结果页(例如基于", + "querystring parameter).": "查询字符串参数)。", + "The total number of results in the page returned (e.g. based off": "返回页面的结果总数(例如基于", + "querystring parameter and actual results returned).": "查询字符串参数和实际返回的结果)。", + "The total number of items available across all pages.": "所有页面上可用的项目总数。", + "We provide a": "我们提供", + "HTTP response header you can parse as shown in the example. This is": "您可以解析 HTTP 响应标头,如示例所示。这是", + "similar to GitHub": "类似于 GitHub", + "(e.g. not all values will be provided if they are not relevant or available, e.g.": "(例如,如果所有值不相关或不可用,则不会提供所有值,例如", + "will not be provided if there is not another page).": "如果没有其他页面,则不会提供)。", + "Unlike other API endpoints, these require": "与其他 API 端点不同,这些端点需要", + "\"username\" equal to the alias username and \"password\" equal to the alias generated password as Basic Authorization headers.": "“用户名”等于别名用户名,“密码”等于别名生成的密码作为基本授权标头。", + "This endpoint section is a work in progress and will be released (hopefully) in 2024. In the interim please use an IMAP client from the \"Apps\" dropdown in the navigation of our website.": "此端点部分正在进行中,预计将于 2024 年发布。在此期间,请使用我们网站导航中“应用程序”下拉菜单中的 IMAP 客户端。", + "CardDAV support is not yet available, follow this discussion on GitHub for updates": "CardDAV 支持尚未提供,请关注 GitHub 上的讨论以获取更新", + "Please ensure that you have followed setup instructions for your domain.": "请确保您已遵循域名的设置说明。", + "These instructions can be found in our FAQ section": "这些说明可以在我们的常见问题解答部分找到", + "Do you support receiving email with IMAP?": "你们支持使用 IMAP 接收电子邮件吗?", + "This will": "这将", + "send an email – it will only simply add the message to your mailbox folder (e.g. this is similar to the IMAP": "发送电子邮件——它只会将消息添加到您的邮箱文件夹(例如,这类似于 IMAP", + "command). If you would like to send an email, then see": "命令)。如果您想发送电子邮件,请参阅", + "below. After creating the outbound SMTP email, then you can append a copy of it using this endpoint to your alias' mailbox for storage purposes.": "下面。创建出站 SMTP 电子邮件后,您可以使用此端点将其副本附加到别名的邮箱中以供存储。", + "Folder endpoints with a folder's path": "带有文件夹路径的文件夹端点", + "as their endpoint are interchangeable with a folder's ID": "因为它们的端点可以与文件夹的 ID 互换", + ". This means you can refer to the folder by either its": "。这意味着您可以通过其", + "These instructions can be found at": "这些说明可以在以下网址找到:", + "Note that this endpoint does not return property values for an email's": "请注意,此端点不会返回电子邮件的属性值", + "Sort by a specific field (prefix with a single hyphen": "按特定字段排序(以单个连字符开头", + "to sort in the reverse direction of that field). Defaults to": "按该字段的反向排序)。默认为", + "if not set.": "如果没有设置。", + "for more insight": "获得更多见解", + "as their endpoint are interchangeable with a domain's ID": "因为它们的端点可以与域的 ID 互换", + "as an additional querystring parameter to the URL for the endpoint query. See": "作为端点查询 URL 的附加查询字符串参数。请参阅", + "(\"SRS\") address here to protect against spoofing with our SRS domain name. We also check the recipient against our": "(“SRS”)地址,以防止使用我们的 SRS 域名进行欺骗。我们还会根据我们的", + "- this is only applicable for outbound SMTP and correlates to the email ID stored in My Account → Emails": "- 这仅适用于出站 SMTP,并与存储在“我的账户”→“电子邮件”中的电子邮件 ID 相关", + "Bank Transfer": "银行转帐", + "Domestic Wire Transfer (Enterprise)": "国内电汇(企业)", + "International Wire Transfer (Enterprise)": "国际电汇(企业)" } \ No newline at end of file diff --git a/package.json b/package.json index 6345a2121..6379f0ed0 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "@ladjs/mongoose": "7.0.0", "@ladjs/mongoose-error-messages": "1.0.0", "@ladjs/passport": "5.1.4", - "@ladjs/pick-original": "1.0.0", + "@ladjs/pick-original": "2.0.0", "@ladjs/policies": "12.1.0", "@ladjs/proxy": "4.0.2", "@ladjs/redis": "1.1.1", diff --git a/routes/api/v1/index.js b/routes/api/v1/index.js index 4be1759bd..617c796a5 100644 --- a/routes/api/v1/index.js +++ b/routes/api/v1/index.js @@ -5,8 +5,10 @@ const Router = require('@koa/router'); const bodyParser = require('koa-bodyparser'); +const dayjs = require('dayjs-with-plugins'); const multer = require('@koa/multer'); const paginate = require('koa-ctx-paginate'); +const { boolean } = require('boolean'); const api = require('#controllers/api'); const policies = require('#helpers/policies'); @@ -167,9 +169,21 @@ router web.myAccount.ensureNotBanned, api.v1.enforcePaidPlan, web.myAccount.ensurePaidToDate, + (ctx, next) => { + // + // starting November 1st we enforce API pagination on this endpoint + // (unless user opts in beforehand using ?pagination=true) + // + const hasPagination = dayjs().isBefore('11/1/2024', 'M/D/YYYY') + ? boolean(ctx.query.pagination) + : true; + if (!hasPagination) return next(); + if (typeof ctx.query.limit === 'undefined') ctx.query.limit = 1000; + return paginate.middleware(50, 1000); + }, web.myAccount.retrieveDomains ) - .get('/domains', api.v1.domains.list) + .get('/domains', web.myAccount.listDomains, api.v1.domains.list) .post( '/domains', web.myAccount.validateDomain, @@ -266,6 +280,18 @@ router ) .get( '/domains/:domain_id/aliases', + (ctx, next) => { + // + // starting November 1st we enforce API pagination on this endpoint + // (unless user opts in beforehand using ?pagination=true) + // + const hasPagination = dayjs().isBefore('11/1/2024', 'M/D/YYYY') + ? boolean(ctx.query.pagination) + : true; + if (!hasPagination) return next(); + if (typeof ctx.query.limit === 'undefined') ctx.query.limit = 1000; + return paginate.middleware(50, 1000); + }, web.myAccount.retrieveAliases, api.v1.aliases.list ) diff --git a/test/api/v1.js b/test/api/v1.js index 17df2643a..e78200d51 100644 --- a/test/api/v1.js +++ b/test/api/v1.js @@ -8,6 +8,7 @@ const { Writable } = require('node:stream'); const ObjectID = require('bson-objectid'); const Redis = require('ioredis-mock'); +const _ = require('lodash'); const dayjs = require('dayjs-with-plugins'); const delay = require('delay'); const getPort = require('get-port'); @@ -30,6 +31,8 @@ const processEmail = require('#helpers/process-email'); const { Logs, Domains, Emails } = require('#models'); const { decrypt } = require('#helpers/encrypt-decrypt'); +const { emoji } = config.views.locals; + const IP_ADDRESS = ip.address(); const client = new Redis(); client.setMaxListeners(0); @@ -95,7 +98,7 @@ test('creates log', async (t) => { await delay(100); const match = await Logs.findOne({ message: log.message }); - t.true(typeof match === 'object'); + t.true(match !== null); }); test('creates domain', async (t) => { @@ -105,6 +108,20 @@ test('creates domain', async (t) => { [config.userFields.planSetAt]: dayjs().startOf('day').toDate() }) .create(); + await utils.paymentFactory + .withState({ + user: user._id, + amount: 300, + invoice_at: dayjs().startOf('day').toDate(), + method: 'free_beta_program', + duration: ms('30d'), + plan: user.plan, + kind: 'one-time' + }) + .create(); + + await user.save(); + const res = await t.context.api .post('/v1/domains') .auth(user[config.userFields.apiToken]) @@ -122,6 +139,21 @@ test('creates alias with global catch-all', async (t) => { [config.userFields.planSetAt]: dayjs().startOf('day').toDate() }) .create(); + + await utils.paymentFactory + .withState({ + user: user._id, + amount: 300, + invoice_at: dayjs().startOf('day').toDate(), + method: 'free_beta_program', + duration: ms('30d'), + plan: user.plan, + kind: 'one-time' + }) + .create(); + + await user.save(); + const domain = await utils.domainFactory .withState({ members: [{ user: user._id, group: 'admin' }], @@ -138,7 +170,162 @@ test('creates alias with global catch-all', async (t) => { }); t.is(res.status, 200); t.is(res.body.name, 'test'); + + t.deepEqual( + _.sortBy(Object.keys(res.body)), + _.sortBy([ + 'created_at', + 'error_code_if_disabled', + 'has_imap', + 'has_pgp', + 'has_recipient_verification', + 'id', + 'is_enabled', + 'locale', + 'name', + 'object', + 'recipients', + 'retention', + 'storage_location', + 'storage_used', + 'updated_at', + 'labels', + 'pending_recipients', + 'verified_recipients', + + 'user', + 'domain' + ]) + ); + + t.deepEqual( + _.sortBy(Object.keys(res.body.user)), + _.sortBy([ + 'address_country', + 'address_html', + 'created_at', + 'display_name', + 'email', + 'full_email', + 'id', + 'last_locale', + 'locale', + 'max_quota_per_alias', + 'object', + 'otp_enabled', + 'plan', + 'updated_at' + ]) + ); + + t.deepEqual( + _.sortBy(Object.keys(res.body.domain)), + _.sortBy([ + 'allowlist', + 'denylist', + 'invites', + 'restricted_alias_names', + 'created_at', + 'has_adult_content_protection', + 'has_catchall', + 'has_custom_verification', + 'has_executable_protection', + 'has_mx_record', + 'has_newsletter', + 'has_phishing_protection', + 'has_recipient_verification', + 'has_regex', + 'has_smtp', + 'has_txt_record', + 'has_virus_protection', + 'id', + 'ignore_mx_check', + 'is_catchall_regex_disabled', + 'locale', + 'max_recipients_per_alias', + 'members', + 'name', + 'object', + 'plan', + 'retention_days', + 'smtp_port', + 'updated_at', + 'verification_record' + ]) + ); + + t.is(res.body.domain.members.length, 1); + + t.deepEqual( + _.sortBy(Object.keys(res.body.domain.members[0])), + _.sortBy(['user', 'group']) + ); + + t.deepEqual( + _.sortBy(Object.keys(res.body.domain.members[0].user)), + _.sortBy(['plan', 'email', 'display_name', 'id']) + ); + t.deepEqual(res.body.recipients, [user.email]); + + // ensures pagination working + { + const res = await t.context.api + .get(`/v1/domains/${domain.name}/aliases`) + .auth(user[config.userFields.apiToken]) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json'); + + t.is(res.status, 200); + + t.is(res.body.length, 1); + + t.deepEqual( + _.sortBy(Object.keys(res.body[0])), + _.sortBy([ + 'labels', + 'verified_recipients', + 'has_pgp', + 'has_imap', + 'storage_used', + 'storage_location', + 'retention', + 'name', + 'is_enabled', + 'error_code_if_disabled', + 'has_recipient_verification', + 'recipients', + 'pending_recipients', + 'id', + 'object', + 'created_at', + 'updated_at', + + 'user', + 'domain' + ]) + ); + + t.deepEqual( + _.sortBy(Object.keys(res.body[0].domain)), + _.sortBy(['name', 'id']) + ); + + t.deepEqual( + _.sortBy(Object.keys(res.body[0].user)), + _.sortBy(['email', 'display_name', 'id']) + ); + + t.is(res.headers['x-page-count'], '1'); + t.is(res.headers['x-page-current'], '1'); + t.is(res.headers['x-page-size'], '1'); + t.is(res.headers['x-item-count'], '1'); + const url = `http://127.0.0.1:${t.context.apiAddress.port}`; + t.is( + res.headers.link, + `<${url}/v1/domains/${domain.name}/aliases?page=1)>; rel="last", <${url}/v1/domains/${domain.name}/aliases?page=1)>; rel="first"` + ); + } }); test('creates alias and generates password', async (t) => { @@ -149,6 +336,20 @@ test('creates alias and generates password', async (t) => { }) .create(); + await utils.paymentFactory + .withState({ + user: user._id, + amount: 300, + invoice_at: dayjs().startOf('day').toDate(), + method: 'free_beta_program', + duration: ms('30d'), + plan: user.plan, + kind: 'one-time' + }) + .create(); + + await user.save(); + const domain = await utils.domainFactory .withState({ members: [{ user: user._id, group: 'admin' }], @@ -188,6 +389,21 @@ test('creates alias with multiple recipients', async (t) => { [config.userFields.planSetAt]: dayjs().startOf('day').toDate() }) .create(); + + await utils.paymentFactory + .withState({ + user: user._id, + amount: 300, + invoice_at: dayjs().startOf('day').toDate(), + method: 'free_beta_program', + duration: ms('30d'), + plan: user.plan, + kind: 'one-time' + }) + .create(); + + await user.save(); + const domain = await utils.domainFactory .withState({ members: [{ user: user._id, group: 'admin' }], @@ -267,8 +483,8 @@ Reply-To: boop@beep.com Message-ID: beep-boop Date: ${date.toISOString()} To: test@foo.com -From: 😊 Test <${alias.name}@${domain.name}> -Subject: testing this +From: ${emoji('blush')} Test <${alias.name}@${domain.name}> +Subject: ${emoji('blush')} testing this Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit @@ -277,15 +493,27 @@ Test`.trim() t.is(res.status, 200); - const header = `=?UTF-8?Q?=C3=B0=C2=9F=C2=98=C2=8A_Test?= <${alias.name}@${domain.name}>`; - // validate header From was converted properly - t.is(res.body.headers.From, header); + t.true( + res.body.message.includes( + `From: ${emoji('blush')} Test <${alias.name}@${domain.name}>` + ) + ); + t.is( + res.body.headers.From, + `${emoji('blush')} Test <${alias.name}@${domain.name}>` + ); + + t.is(res.body.headers.Subject, `${emoji('blush')} testing this`); // validate message body was converted as well const email = await Emails.findOne({ id: res.body.id }); - const message = await Emails.getMessage(email.message); - t.true(message.toString().includes('From: ' + header)); + const message = await Emails.getMessage(email.message, true); + t.true( + message.includes( + `From: ${emoji('blush')} Test <${alias.name}@${domain.name}>` + ) + ); // validate envelope t.is(res.body.envelope.from, `${alias.name}@${domain.name}`); @@ -300,8 +528,19 @@ Test`.trim() ].sort() ); + // // validate message-id - t.is(res.body.messageId, ''); + // + // NOTE: we do not ensureMessageId format for the following headers + // - references + // - message-id + // - in-reply-to + // + // + // + // t.is(res.body.messageId, ''); + // + t.is(res.body.messageId, 'beep-boop'); // validate date t.is(new Date(res.body.date).getTime(), date.getTime()); @@ -968,6 +1207,95 @@ test('create domain without catchall', async (t) => { t.is(res.status, 200); } + // list aliases for the domain should paginate response + { + const res = await t.context.api + .get(`/v1/domains/testdomain1.com/aliases`) + .auth(user[config.userFields.apiToken]) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json'); + + t.is(res.status, 200); + t.deepEqual(res.body, []); + t.is(res.headers['x-page-count'], '1'); + t.is(res.headers['x-page-current'], '1'); + t.is(res.headers['x-page-size'], '1'); + t.is(res.headers['x-item-count'], '0'); + const url = `http://127.0.0.1:${t.context.apiAddress.port}`; + t.is( + res.headers.link, + `<${url}/v1/domains/testdomain1.com/aliases?page=1)>; rel="last", <${url}/v1/domains/testdomain1.com/aliases?page=1)>; rel="first"` + ); + } + + // list domains should paginate response + { + const res = await t.context.api + .get('/v1/domains') + .auth(user[config.userFields.apiToken]) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json'); + + t.is(res.status, 200); + t.is(res.body.length, 1); + t.true(res.body[0].name === 'testdomain1.com'); + t.true(res.body[0].plan === 'enhanced_protection'); + // filter for properties for exposed values + t.deepEqual( + _.sortBy(Object.keys(res.body[0])), + _.sortBy([ + 'allowlist', + 'denylist', + 'created_at', + 'restricted_alias_names', + 'has_adult_content_protection', + 'has_catchall', + 'has_custom_verification', + 'has_executable_protection', + 'has_mx_record', + 'has_newsletter', + 'has_phishing_protection', + 'has_recipient_verification', + 'has_regex', + 'has_smtp', + 'has_txt_record', + 'has_virus_protection', + 'id', + 'ignore_mx_check', + 'is_catchall_regex_disabled', + 'max_recipients_per_alias', + 'name', + 'object', + 'plan', + 'retention_days', + 'smtp_port', + 'updated_at', + 'verification_record', + // + // NOTE: paid plans additionally expose these three properties: + // (see `app/controllers/web/my-account/list-domains.js`) + // - storage_used + // - storage_used_by_aliases + // - storage_quota + // + 'storage_used', + 'storage_used_by_aliases', + 'storage_quota', + // added by API v1 domains controller as a helper + 'link' + ]) + ); + t.is(res.headers['x-page-count'], '1'); + t.is(res.headers['x-page-current'], '1'); + t.is(res.headers['x-page-size'], '1'); + t.is(res.headers['x-item-count'], '1'); + const url = `http://127.0.0.1:${t.context.apiAddress.port}`; + t.is( + res.headers.link, + `<${url}/v1/domains?page=1)>; rel="last", <${url}/v1/domains?page=1)>; rel="first"` + ); + } + { const res = await t.context.api .post('/v1/domains') @@ -1058,16 +1386,85 @@ test('lists emails', async (t) => { .send({ from: `${alias.name}@${domain.name}`, to: 'foo@bar.com', - subject: 'beep', + subject: `${emoji('tada')} beep`, text: 'yo' }); t.is(res.status, 200); t.true(typeof res.body.id === 'string'); - t.is(res.body.subject, 'beep'); + t.is(res.body.subject, `${emoji('tada')} beep`); + t.is(res.body.headers.Subject, `${emoji('tada')} beep`); + t.deepEqual( + _.sortBy(Object.keys(res.body)), + _.sortBy([ + 'rejectedErrors', + 'accepted', + 'alias', + 'created_at', + 'date', + 'domain', + 'envelope', + 'hard_bounces', + 'headers', + 'id', + 'is_bounce', + 'is_locked', + 'is_redacted', + 'link', + 'message', + 'messageId', + 'object', + 'soft_bounces', + 'status', + 'subject', + 'updated_at', + 'user' + ]) + ); + t.true(typeof res.body.message === 'string'); id = res.body.id; } + { + const res = await t.context.api + .get(`/v1/emails/${id}`) + .auth(user[config.userFields.apiToken]) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json'); + t.is(res.status, 200); + t.true(typeof res.body.id === 'string'); + t.is(res.body.subject, `${emoji('tada')} beep`); + t.is(res.body.headers.Subject, `${emoji('tada')} beep`); + t.deepEqual( + _.sortBy(Object.keys(res.body)), + _.sortBy([ + 'rejectedErrors', + 'accepted', + 'alias', + 'created_at', + 'date', + 'domain', + 'envelope', + 'hard_bounces', + 'headers', + 'id', + 'is_bounce', + 'is_locked', + 'is_redacted', + 'link', + 'message', + 'messageId', + 'object', + 'soft_bounces', + 'status', + 'subject', + 'updated_at', + 'user' + ]) + ); + t.true(typeof res.body.message === 'string'); + } + { const res = await t.context.api .get('/v1/emails') @@ -1075,8 +1472,43 @@ test('lists emails', async (t) => { .set('Accept', 'application/json'); t.is(res.status, 200); + t.is(res.headers['x-page-count'], '1'); + t.is(res.headers['x-page-current'], '1'); + t.is(res.headers['x-page-size'], '1'); + t.is(res.headers['x-item-count'], '1'); + const url = `http://127.0.0.1:${t.context.apiAddress.port}`; + t.is( + res.headers.link, + `<${url}/v1/emails?page=1)>; rel="last", <${url}/v1/emails?page=1)>; rel="first"` + ); + t.is(res.body[0].id, id); - t.is(res.body[0].subject, 'beep'); + t.is(res.body[0].subject, `${emoji('tada')} beep`); + + t.deepEqual( + _.sortBy(Object.keys(res.body[0])), + _.sortBy([ + 'accepted', + 'alias', + 'created_at', + 'date', + 'domain', + 'envelope', + 'hard_bounces', + 'id', + 'is_bounce', + 'is_locked', + 'is_redacted', + 'link', + 'messageId', + 'object', + 'soft_bounces', + 'status', + 'subject', + 'updated_at', + 'user' + ]) + ); } }); @@ -1448,6 +1880,20 @@ test('error_code_if_disabled', async (t) => { }) .create(); + await utils.paymentFactory + .withState({ + user: user._id, + amount: 300, + invoice_at: dayjs().startOf('day').toDate(), + method: 'free_beta_program', + duration: ms('30d'), + plan: user.plan, + kind: 'one-time' + }) + .create(); + + await user.save(); + let domain; { const res = await t.context.api diff --git a/test/caldav/index.js b/test/caldav/index.js index ab75f3f35..d15bc18b7 100644 --- a/test/caldav/index.js +++ b/test/caldav/index.js @@ -8,13 +8,14 @@ const path = require('node:path'); const Redis = require('ioredis-mock'); const dayjs = require('dayjs-with-plugins'); +const getPort = require('get-port'); const ip = require('ip'); const ms = require('ms'); -const test = require('ava'); -const tsdav = require('tsdav'); -const getPort = require('get-port'); +const pWaitFor = require('p-wait-for'); const sharedConfig = require('@ladjs/shared-config'); const splitLines = require('split-lines'); +const test = require('ava'); +const tsdav = require('tsdav'); const utils = require('../utils'); const CalDAV = require('../../caldav-server'); @@ -443,14 +444,26 @@ test('it should send calendar invite', async (t) => { t.true(response.ok); - const email = await Emails.findOne({ - alias: t.context.alias._id, - status: 'queued', - subject: '15 Min Meeting between Forward Email and You' - }) - .lean() - .exec(); - t.true(typeof email === 'object'); + // + // invites are sent in background + // (promise returns early for creating event) + // + let email; + await pWaitFor( + async () => { + email = await Emails.findOne({ + alias: t.context.alias._id, + status: 'queued', + subject: 'Invitation: 15 Min Meeting between Forward Email and You' + }) + .lean() + .exec(); + return email !== null; + }, + { timeout: ms('5s') } + ); + + t.true(email !== null); }); test('fetchCalendarObjects should be able to fetch calendar objects', async (t) => { diff --git a/test/helpers.js b/test/helpers.js index 4f6415e8e..27e689196 100644 --- a/test/helpers.js +++ b/test/helpers.js @@ -38,7 +38,7 @@ test('creates instance', async (t) => { const tangerine = createTangerine(client); await tangerine.resolve('forwardemail.net'); const result = await client.get('tangerine:a:forwardemail.net'); - t.true(typeof result === 'object'); + t.true(result !== null); t.true(result.answers.length > 0); t.true(result.answers[0].name === 'forwardemail.net'); }); diff --git a/test/smtp/index.js b/test/smtp/index.js index e7be3b9bd..1ae1dcbeb 100644 --- a/test/smtp/index.js +++ b/test/smtp/index.js @@ -1103,7 +1103,8 @@ test(`IDN domain`, async (t) => { await user.save(); - const resolver = createTangerine(t.context.client, logger); + const smtp = new SMTP({ client: t.context.client }, false); + const { resolver } = smtp; const domain = await utils.domainFactory .withState({ @@ -1123,6 +1124,9 @@ test(`IDN domain`, async (t) => { }) .create(); + const pass = await alias.createToken(); + await alias.save(); + const map = new Map(); // spoof test@test.com mx records @@ -1257,6 +1261,80 @@ test(`IDN domain`, async (t) => { client }) ); + + // run do a similar test using SMTP connection + const port = await getPort(); + await smtp.listen(port); + + const mx = await asyncMxConnect({ + target: IP_ADDRESS, + port: smtp.server.address().port, + dnsOptions: { + // + resolve: util.callbackify(resolver.resolve.bind(resolver)) + } + }); + + const transporter = nodemailer.createTransport({ + logger, + debug: true, + host: mx.host, + port: mx.port, + connection: mx.socket, + // ignoreTLS: true, + // set `secure` to `true` for port 465 otherwise `false` for port 587, 2587, 25, and 2525 + secure: false, + tls: { + rejectUnauthorized: false + }, + auth: { + user: `${alias.name}@${domain.name}`, + pass + } + }); + + const messageId = `${randomstring({ + characters: 'abcdefghijklmnopqrstuvwxyz0123456789', + length: 10 + })}@${domain.name}`; + + await transporter.sendMail({ + envelope: { + from: `${alias.name}@${domain.name}`, + to: 'test@foo.com' + }, + raw: ` +Message-ID: <${messageId}> +To: test@test.com +List-Unsubscribe: foo@foo.com +From: Test <${alias.name}@${domain.name}> +Subject: testing this +Content-Type: text/plain; charset=us-ascii +Content-Transfer-Encoding: 7bit + +Test`.trim() + }); + + { + const email = await Emails.findOne({ + messageId + }) + .lean() + .exec(); + t.true(email !== null); + + // + // process the email + // + await t.notThrowsAsync( + processEmail({ + email, + port: testPort, + resolver, + client + }) + ); + } }); test(`10MB message size`, async (t) => { @@ -1836,10 +1914,10 @@ test('smtp outbound queue', async (t) => { } }); - const messageId = `<${randomstring({ + const messageId = `${randomstring({ characters: 'abcdefghijklmnopqrstuvwxyz0123456789', length: 10 - })}@${domain.name}>`; + })}@${domain.name}`; const RCPT_TO = [ 'a@xyz.com', @@ -1859,7 +1937,7 @@ Sender: baz@beep.com Cc: beep@boop.com,beep@boop.com Bcc: foo@bar.com,a@xyz.com,b@xyz.com Reply-To: Beep boop@beep.com -Message-ID: ${messageId} +Message-ID: <${messageId}> To: test@foo.com From: Test <${alias.name}@${domain.name}> Subject: testing this @@ -1888,10 +1966,9 @@ Test`.trim() }) .lean() .exec(); - t.true(typeof email === 'object'); - // TODO: validate by message-id too to ensure it's the right email + t.true(email !== null); t.is(email.headers.From, `Test <${alias.name}@${domain.name}>`); - t.is(email.headers['Reply-To'], 'Beep '); + t.is(email.headers['Reply-To'], 'Beep boop@beep.com'); t.is(email.status, 'queued'); // validate envelope @@ -2392,10 +2469,10 @@ test('does not allow differing domain with domain-wide catch-all', async (t) => } }); - const messageId = `<${randomstring({ + const messageId = `${randomstring({ characters: 'abcdefghijklmnopqrstuvwxyz0123456789', length: 10 - })}@${domain.name}>`; + })}@${domain.name}`; const err = await t.throwsAsync( transporter.sendMail({ @@ -2404,7 +2481,7 @@ test('does not allow differing domain with domain-wide catch-all', async (t) => to: 'test@foo.com' }, raw: ` -Message-ID: ${messageId} +Message-ID: <${messageId}> To: test@foo.com From: Test <${alias.name}@someotherdomain.com> Subject: testing this @@ -2571,10 +2648,10 @@ test('requires newsletter approval', async (t) => { } }); - const messageId = `<${randomstring({ + const messageId = `${randomstring({ characters: 'abcdefghijklmnopqrstuvwxyz0123456789', length: 10 - })}@${domain.name}>`; + })}@${domain.name}`; await transporter.sendMail({ envelope: { @@ -2582,7 +2659,7 @@ test('requires newsletter approval', async (t) => { to: 'test@foo.com' }, raw: ` -Message-ID: ${messageId} +Message-ID: <${messageId}> To: test@foo.com List-Unsubscribe: foo@foo.com From: Test <${alias.name}@${domain.name}> @@ -2598,7 +2675,7 @@ Test`.trim() }) .lean() .exec(); - t.true(typeof email === 'object'); + t.true(email !== null); // // process the email diff --git a/test/utils.js b/test/utils.js index 27d3df15a..db5c601b9 100644 --- a/test/utils.js +++ b/test/utils.js @@ -84,7 +84,9 @@ exports.setupApiServer = async (t) => { ); const port = await getPort(); t.context.client = client; - t.context.api = request.agent(api.app.listen(port)); + const instance = await api.app.listen(port); + t.context.api = request.agent(instance); + t.context.apiAddress = instance.address(); }; exports.setupSMTPServer = async (t) => { diff --git a/test/web/snapshots/index.js.md b/test/web/snapshots/index.js.md index 5802de662..413681f15 100644 --- a/test/web/snapshots/index.js.md +++ b/test/web/snapshots/index.js.md @@ -24,7 +24,7 @@ Generated by [AVA](https://avajs.dev). signed forwards don't trip email filters 👏. I'm a happy user! ❤️
Creator of Ruby on Rails, Founder & CTO at Basecamp & HEY
abhinemani
abhi nemaniVerified
@abhinemani
Have now switched email forwarding from MailGun to ForwardEmail.net␊ . Simple and painless (and free!). Just some DNS changes, and it just works. Thanks
Government Technology Advisor, Sacramento and Los Angeles
andrewe
Andrew Escobar (Andres)Verified
@andrewe
This is so dope. Thank you. forwardemail.net
Fintech Explorer and Open Finance Advocate
stigi
Ullrich Schäfer
@stigi
Thanks so much for forwardemail.net␊ ! It solves a real problem for our little org!
Mobile Lead at Pitch, Formerly at Facebook and Soundcloud
andregce
Andre Goncalves
@andregce
So they made this cool app that forwards email from your own domain to your Gmail inbox. There is even a catch all option, so sales@, support@, etc all goes to your own inbox. Check it out! It's free! forwardemail.net
Computer Engineer, Software Developer
philcockfield
Phil
@philcockfield
Thanks for your forwardemail.net␊ - . What you've done is a beautiful thing! Your FAQ just smacks of integrity, and is just the thing I need.
hypersheet, db.team

Open-source

Unlike other services, we do not store logs (with the exception of errors and outbound SMTP) and are 100% open-source. We're the only service that never stores nor writes to disk any emails – it's all done in-memory.

Features

Privacy-focused

We created this service because you have a right to privacy. Existing services did not respect it. We use robust encryption with TLS, do not store SMTP logs (with the exception of errors and outbound SMTP), and do not write your emails to disk storage.

Regain your privacy Regain your privacy

Disposable Addresses

Create a specific or an anonymous email address that forwards to you. You can even assign it a label and enable or disable it at any time to keep your inbox tidy. Your actual email address is never exposed.

Disposable addresses Disposable addresses

Multiple Recipients and Wildcards

You can forward a single address to multiple, and even use wildcard addresses – also known as catch-all's. Managing your company's inboxes has never been easier.

Start forwarding now Start forwarding now

"Send mail as" with Gmail and Outlook

You'll never have to leave your inbox to send out emails as if they're from your company. Send and reply-to messages as if they're from you@company.com directly from you@gmail.com or you@outlook.com.

Configure your inbox Configure your inbox

Enterprise-grade

We're email security and deliverability experts.

  • Protection against phishing, malware, viruses, and spam.
  • Industry standard checks for DMARC, SPF, DKIM, SRS, ARC, and MTA-STS.
  • SOC 2 Type 2 compliant bare metal servers from Vultr and Digital Ocean.
  • Unlike other services, we use 100% open-source software.
  • Backscatter prevention, denylists, and rate limiting.
  • Global load balancers and application-level DNS over HTTPS ("DoH").