Setting Up Forwarding

9 views Markdown

The six endpoints carrying what arrives at a domain somewhere else.

Overview

Forwarding is carrying what arrives at a domain somewhere else. It comes in two kinds and both sit behind the same add-on: mail forwarding carries the post, and address forwarding carries the visitor.

The two differ in number: mail forwarding is a list with a rule per local part, while an address forward is one per domain.

Forwarding is not hosting. No mail is stored and no page is served; what arrives is handed on to another address and nothing more.

Reference

Listing the Mail Forwards

get/api/v1/client/domains/{domain}/email-forwards
Domains/GetEmailForwards an add-on is needed

Returns the mail forwards defined on the domain.

Response fields data[] — 4
identitystringThe record id on the provider's side. A steady value is worked out from the source and target where the provider gives none.
prefixstringThe local part on the domain. It sits left of the sign.
sourcestringThe full source address. It is always the local part joined to the domain.
targetstringThe box the mail goes to.
Errors 5
not_found404No such domain, it is not yours, or access to it is restricted.
addon_required422The forwarding add-on was not bought. An unpaid invoice and an extension that does not offer it fall at the same gate.
addon_pending422The add-on invoice is unpaid. Its id comes in the answer's detail.
email_forwarding_not_supported422The provider module lacks mail forwarding.
email_forwarding_failed500The live read failed.
Request
curl 'https://panel.example.com/api/v1/client/domains/example.com/email-forwards' \
  -H "Authorization: Bearer $CLIENT_KEY"
const res = await fetch(`https://panel.example.com/api/v1/client/domains/${domain}/email-forwards`, {
  headers: { Authorization: `Bearer ${clientKey}` },
});

if (res.status === 422) return offerAddon(await res.json());

const { data } = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/client/domains/' . $domain . '/email-forwards');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $clientKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// A forward is NOT A MAILBOX: the mail arriving passes to another address and is kept nowhere here.
$rows = Kernel::internal('client:Domains/GetEmailForwards',
    ['owner_id' => $uid, 'domain' => $domain])['data'];

Adding a Mail Forward

post/api/v1/client/domains/{domain}/email-forwards
Domains/CreateEmailForward an add-on is needed

Adds a rule carrying mail for the domain to another box.

Body 2
prefixstringreqThe local part on the domain. The forward answers for that part joined to the domain.
targetstringreqThe target box. It has to be a valid e-mail address.
Response fields data[] — 4
dataarrayThe list read afresh after the add. Same shape as the listing endpoint.
Errors 8
not_found404No such domain, it is not yours, or access to it is restricted.
addon_required422The forwarding add-on was not bought. An unpaid invoice and an extension that does not offer it fall at the same gate.
not_actionable422The domain is not live.
email_forward_fields422The local part or the target is missing.
email_forward_target_invalid422The target is not a valid e-mail address.
email_forwarding_not_supported422The provider module lacks the support.
email_forward_rejected422A hook refused the change.
email_forwarding_failed422The provider refused the rule.
Request
curl -X POST 'https://panel.example.com/api/v1/client/domains/example.com/email-forwards' \
  -H "Authorization: Bearer $CLIENT_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"prefix":"sales","target":"[email protected]"}'
const res = await fetch(`https://panel.example.com/api/v1/client/domains/${domain}/email-forwards`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${clientKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ prefix, target }),
});

const { data } = await res.json();
renderForwards(data);
$ch = curl_init('https://panel.example.com/api/v1/client/domains/' . $domain . '/email-forwards');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $clientKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(compact('prefix', 'target')),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// Send THE LOCAL PART alone: writing a full address adds the domain twice and breaks the rule.
Kernel::internal('client:Domains/CreateEmailForward',
    ['owner_id' => $uid, 'domain' => $domain, 'prefix' => 'sales', 'target' => $box]);

Removing a Mail Forward

delete/api/v1/client/domains/{domain}/email-forwards
Domains/DeleteEmailForward the match narrows

Removes a mail forwarding rule.

Body 3
prefixstringreqThe local part of the rule to remove.
targetstringThe target. Send it where the provider keys on the source and the target together.
identitystringThe record id from the listing. Send it where you hold one.
Response fields data[] — 4
dataarrayThe list read afresh after the removal.
Errors 6
not_found404No such domain, it is not yours, or access to it is restricted.
addon_required422The forwarding add-on was not bought. An unpaid invoice and an extension that does not offer it fall at the same gate.
not_actionable422The domain is not live.
email_forward_fields422The local part was not sent.
email_forwarding_not_supported422The provider module lacks the support.
email_forwarding_failed422The provider refused the removal.
Request
curl -X DELETE 'https://panel.example.com/api/v1/client/domains/example.com/email-forwards' \
  -H "Authorization: Bearer $CLIENT_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"prefix":"sales","target":"[email protected]"}'
const res = await fetch(`https://panel.example.com/api/v1/client/domains/${domain}/email-forwards`, {
  method: 'DELETE',
  headers: {
    Authorization: `Bearer ${clientKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ prefix: f.prefix, target: f.target, identity: f.identity }),
});

const { data } = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/client/domains/' . $domain . '/email-forwards');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'DELETE',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $clientKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode($selector),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// One local part can reach SEVERAL targets: send the target too, or they can all go.
Kernel::internal('client:Domains/DeleteEmailForward', ['owner_id' => $uid, 'domain' => $domain,
    'prefix' => $f['prefix'], 'target' => $f['target'], 'identity' => $f['identity']]);

Reading the Address Forward

get/api/v1/client/domains/{domain}/forwarding
Domains/GetUrlForwarding an add-on is needed

Returns whether the domain sends visitors on to another address.

Response fields data — 5
activeboolWhether a forward is set up.
protocolstringThe target's scheme.
methodintThe kind of forward. Permanent or temporary.
domainstringThe target without its scheme. It comes empty where none is set up.
urlstringThe full target address.
Errors 5
not_found404No such domain, it is not yours, or access to it is restricted.
addon_required422The forwarding add-on was not bought. An unpaid invoice and an extension that does not offer it fall at the same gate.
addon_pending422The add-on invoice is unpaid.
url_forwarding_not_supported422The provider module lacks address forwarding.
url_forwarding_failed500The live read failed.
Request
curl 'https://panel.example.com/api/v1/client/domains/example.com/forwarding' \
  -H "Authorization: Bearer $CLIENT_KEY"
const res = await fetch(`https://panel.example.com/api/v1/client/domains/${domain}/forwarding`, {
  headers: { Authorization: `Bearer ${clientKey}` },
});

const { data } = await res.json();
if (data.active) showTarget(data.url, data.method);
$ch = curl_init('https://panel.example.com/api/v1/client/domains/' . $domain . '/forwarding');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $clientKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// There is ONE forward per domain: setting a new one writes over the old, and no list exists.
$f = Kernel::internal('client:Domains/GetUrlForwarding',
    ['owner_id' => $uid, 'domain' => $domain])['data'];

Setting Up an Address Forward

put/api/v1/client/domains/{domain}/forwarding
Domains/UpdateUrlForwarding an add-on is needed

Sends a visitor arriving at the domain on to another address.

Body 2
urlstringreqThe full target address. Its scheme becomes the forward's, and the insecure one stands in when none is written.
methodintThe kind of forward. Permanent is the default and another value falls to it.
Response fields data — 5
dataobjectThe forward as it now stands. Same shape as the read endpoint.
Errors 7
not_found404No such domain, it is not yours, or access to it is restricted.
addon_required422The forwarding add-on was not bought. An unpaid invoice and an extension that does not offer it fall at the same gate.
not_actionable422The domain is not live.
url_required422The target was not sent, or nothing is left once the scheme is taken off.
url_forwarding_not_supported422The provider module lacks the support.
url_forwarding_rejected422A hook refused the change.
url_forwarding_failed422The provider refused the change.
Request
curl -X PUT 'https://panel.example.com/api/v1/client/domains/example.com/forwarding' \
  -H "Authorization: Bearer $CLIENT_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"url":"https://shop.example.net/welcome","method":301}'
const res = await fetch(`https://panel.example.com/api/v1/client/domains/${domain}/forwarding`, {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${clientKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ url, method: 302 }),
});

const { data } = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/client/domains/' . $domain . '/forwarding');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'PUT',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $clientKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(['url' => $target, 'method' => 301]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// Browsers CACHE a permanent forward: pick the temporary kind while testing and move to permanent after.
Kernel::internal('client:Domains/UpdateUrlForwarding',
    ['owner_id' => $uid, 'domain' => $domain, 'url' => $target, 'method' => 302]);

Removing the Address Forward

delete/api/v1/client/domains/{domain}/forwarding
Domains/DeleteUrlForwarding an add-on is needed

Removes the domain's address forward.

Response fields data — 5
dataobjectThe state read after the removal. Same shape as the read endpoint.
Errors 6
not_found404No such domain, it is not yours, or access to it is restricted.
addon_required422The forwarding add-on was not bought. An unpaid invoice and an extension that does not offer it fall at the same gate.
not_actionable422The domain is not live.
url_forwarding_not_supported422The provider module lacks the support.
url_forwarding_rejected422A hook refused the removal.
url_forwarding_failed422The provider refused the removal.
Request
curl -X DELETE 'https://panel.example.com/api/v1/client/domains/example.com/forwarding' \
  -H "Authorization: Bearer $CLIENT_KEY"
const res = await fetch(`https://panel.example.com/api/v1/client/domains/${domain}/forwarding`, {
  method: 'DELETE',
  headers: { Authorization: `Bearer ${clientKey}` },
});

const { data } = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/client/domains/' . $domain . '/forwarding');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'DELETE',
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $clientKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// Removing the forward leaves the domain pointing NOWHERE: a visitor lands on nothing.
// Think first about what takes its place; a record or a new target is wanted.
Kernel::internal('client:Domains/DeleteUrlForwarding',
    ['owner_id' => $uid, 'domain' => $domain]);

Pitfalls

Both kinds rest on one add-on

All six endpoints of mail and address forwarding sit behind the forwarding add-on. Unbought, or with its invoice unpaid, they all refuse and the answer says which case it is. One purchase opens them both.

One address forward per domain

An address forward has no list: setting one writes over what was there. There is no adding a second target, and a second call replaces the first. Mail forwarding is a list and carries as many rules as you like.

The local part goes, not the full address

The source field on a mail forward takes the local part alone and the server adds the domain. Writing a full address adds the domain twice and the rule answers no mail. The source field in the answer shows the right joining.

Removing without a target can take several rules

One local part can forward to several targets. Sending it alone on a removal can take every rule bound to that part. Add the target, and the record id where you hold one.

A permanent forward is kept by the browser

Picking the permanent kind tells browsers and search engines the address moved for good, and they keep that for a long while. A permanent forward to a wrong target sends visitors there for a time even after the fix. Use the temporary kind while testing.

A forward is not a mailbox

A mail forward passes the post to another box and keeps no copy. Where the target box is full or refuses the mail, the message is lost with no trace here. A customer wanting a real box should take a mail service.

Was this helpful?

Thanks for your feedback!

Still Need Help?

Our support team is here around the clock for anything you can't find above.