Email Afmeld System - Teknisk Dokumentation

📧 Email Afmeld System - Udtømmende Teknisk Dokumentation

Version: 2.0
Dato: Januar 2026
System: Loanly24 Email Marketing Platform


📋 System Oversigt

Email afmeld-systemet er en multi-layer arkitektur der håndterer email opt-out compliance i henhold til GDPR og dansk lovgivning.

Core Komponenter

  1. Afmeld Links - Embedded i alle email templates
  2. handleEmailUnsubscribe - Backend POST endpoint til processering
  3. EmailAfmeldConfirm - Frontend bekræftelsesside
  4. EmailOptOut - Dedikeret afmeld entity
  5. EmailOptOutLog - Audit trail for compliance
  6. UnifiedUser - Master database med consent status
  7. reactivateEmailConsent - Admin genaktivering
  8. Brevo Webhook - Email provider integration
  9. sendEmailFromQueue - Queue processor med opt-out check

🗄️ Database Struktur

1. EmailOptOut Entity

Formål: Dedikeret opt-out database, hurtig lookup performance

{
  "name": "EmailOptOut",
  "properties": {
    "email": {
      "type": "string",
      "format": "email",
      "description": "Email adresse (normaliseret lowercase+trim)"
    },
    "opted_out": {
      "type": "boolean",
      "default": true,
      "description": "Nuværende opt-out status"
    },
    "opted_out_at": {
      "type": "string",
      "format": "date-time",
      "description": "Timestamp for afmelding"
    },
    "opted_in_at": {
      "type": "string",
      "format": "date-time",
      "description": "Timestamp for evt. gentilmelding"
    },
    "contact_id": {
      "type": "string",
      "description": "Reference til EmailContact eller Lead (optional)"
    },
    "source": {
      "type": "string",
      "description": "Afmeldings-kilde: 'link', 'manual', 'brevo_webhook'"
    }
  },
  "required": ["email", "opted_out"]
}

Design Rationale:

  • Normalisering: Email gemmes altid som lowercase().trim() for konsistent lookup
  • Boolean flag: opted_out tillader både opt-out og opt-in states
  • Timestamps: Både opted_out_at og opted_in_at for fuld historik
  • Source tracking: Sporer hvor afmeldingen kom fra

2. EmailOptOutLog Entity

Formål: Immutable audit trail for alle opt-out/opt-in handlinger (GDPR compliance)

{
  "name": "EmailOptOutLog",
  "properties": {
    "email": {
      "type": "string",
      "format": "email",
      "description": "Email adresse"
    },
    "action": {
      "type": "string",
      "enum": ["opt_out", "opt_in"],
      "description": "Type handling"
    },
    "source": {
      "type": "string",
      "description": "Kilde: 'link', 'manual', 'forced_reactivation', 'brevo_webhook'"
    },
    "performed_by": {
      "type": "string",
      "description": "Email på bruger der udførte handlingen (admin eller 'system')"
    },
    "ip_address": {
      "type": "string",
      "description": "IP adresse fra request"
    },
    "user_agent": {
      "type": "string",
      "description": "Browser user agent"
    },
    "notes": {
      "type": "string",
      "description": "Eventuelle noter/kommentarer"
    },
    "email_opt_out_id": {
      "type": "string",
      "description": "Reference til EmailOptOut record"
    }
  },
  "required": ["email", "action", "performed_by", "ip_address"]
}

Design Rationale:

  • Immutable: Records slettes aldrig, kun appended
  • IP + User Agent: Fuld forensic trail
  • performed_by: Sporer hvem der udførte handlingen (admin email eller 'system')
  • Compliance: Opfylder GDPR krav om dokumentation af consent changes

3. UnifiedUser Entity (Master Database)

Formål: Central bruger-database med consent status

{
  "properties": {
    "email": "string (unique primary key)",
    "consent_email": "boolean (default: true)",
    "consent_sms": "boolean (default: false)",
    "status": "enum ['active', 'unsubscribed', 'bounced', 'complained']",
    "consent_timestamp": "date-time",
    "last_activity_at": "date-time",
    ...
  }
}

Opt-Out Impact:

  • consent_emailfalse
  • status'unsubscribed'
  • last_activity_at → opdateres til nu

4. EmailContact Entity

Formål: Email marketing contacts database

{
  "properties": {
    "email": "string (unique)",
    "status": "enum ['active', 'suppressed', 'bounced', 'complained']",
    "unsubscribed_at": "date-time",
    "unsubscribe_reason": "string",
    ...
  }
}

Opt-Out Impact:

  • status'suppressed'
  • unsubscribed_at → timestamp

🔄 Data Flow - Afmelding

Step-by-Step Process

┌─────────────────────────────────────────────────────────┐
│ 1. User clicks afmeld link i email                     │
│    URL: /api/functions/handleEmailUnsubscribe?         │
│         email=user@example.com                          │
└─────────────────────────────────────────────────────────┘
                         ↓
┌─────────────────────────────────────────────────────────┐
│ 2. handleEmailUnsubscribe (POST)                        │
│    - Modtager email parameter                           │
│    - Validerer email format                             │
│    - Henter IP + user agent fra request                 │
└─────────────────────────────────────────────────────────┘
                         ↓
┌─────────────────────────────────────────────────────────┐
│ 3. Database Updates (parallel transactions)             │
│                                                          │
│    A) EmailOptOut (create/update)                       │
│       - Normaliserer email: toLowerCase().trim()        │
│       - Checker om record eksisterer                    │
│       - CREATE ny eller UPDATE opted_out=true           │
│       - Sætter opted_out_at timestamp                   │
│       - source = 'link'                                 │
│                                                          │
│    B) EmailOptOutLog (create - immutable)               │
│       - action: 'opt_out'                               │
│       - email, ip_address, user_agent                   │
│       - performed_by: 'system'                          │
│       - source: 'link'                                  │
│       - email_opt_out_id: reference til OptOut          │
│                                                          │
│    C) UnifiedUser (update)                              │
│       - Filter by email (normalized)                    │
│       - consent_email = false                           │
│       - status = 'unsubscribed'                         │
│       - last_activity_at = now                          │
│                                                          │
│    D) UserEvent (create - audit log)                    │
│       - event_type: 'email_unsubscribed'                │
│       - email, event_timestamp                          │
│       - channel: 'email'                                │
│       - metadata: { source: 'link', ip, user_agent }    │
│                                                          │
│    E) EmailContact (update hvis exists)                 │
│       - Filter by email                                 │
│       - status = 'suppressed'                           │
│       - unsubscribed_at = now                           │
│       - unsubscribe_reason = 'User opt-out via link'    │
│                                                          │
│    F) Lead (update hvis exists)                         │
│       - Filter by email                                 │
│       - status = 'unsubscribed' (custom tracking)       │
└─────────────────────────────────────────────────────────┘
                         ↓
┌─────────────────────────────────────────────────────────┐
│ 4. Response til frontend                                │
│    JSON: { success: true, email: "user@example.com" }  │
└─────────────────────────────────────────────────────────┘

🔧 Backend Funktioner

1. handleEmailUnsubscribe

Path: functions/handleEmailUnsubscribe.js
Method: POST
Public: Ja (ingen auth krævet)

Input:

{
  "email": "user@example.com"
}

Process:

  1. Ekstraherer IP + User Agent fra request headers
  2. Normaliserer email: email.toLowerCase().trim()
  3. Parallel database opdateringer (se Data Flow)
  4. Håndterer fejl gracefully (fortsætter selv ved partial failure)

Output:

{
  "success": true,
  "email": "user@example.com"
}

Error Handling:

  • Try-catch blocks omkring hver entity operation
  • Logs fejl til console men fejler ikke helt
  • Returnerer success hvis minimum ét update lykkedes

Code Snippet:

const base44 = createClientFromRequest(req);
const { email } = await req.json();
const normalizedEmail = email.toLowerCase().trim();
const now = new Date().toISOString();

// Get IP + User Agent
const ip = req.headers.get('x-forwarded-for') || 
           req.headers.get('x-real-ip') || 
           'unknown';
const userAgent = req.headers.get('user-agent') || 'unknown';

// Create/update EmailOptOut
const existingOptOuts = await base44.asServiceRole.entities
  .EmailOptOut.filter({ email: normalizedEmail });

if (existingOptOuts.length > 0) {
  await base44.asServiceRole.entities.EmailOptOut
    .update(existingOptOuts[0].id, {
      opted_out: true,
      opted_out_at: now,
      source: 'link'
    });
} else {
  await base44.asServiceRole.entities.EmailOptOut.create({
    email: normalizedEmail,
    opted_out: true,
    opted_out_at: now,
    source: 'link'
  });
}

2. reactivateEmailConsent

Path: functions/reactivateEmailConsent.js
Method: POST
Auth: Admin only (user.role === 'admin')

Formål: Tillader admin at genaktivere email consent for en bruger

Input:

{
  "userId": "unified-user-id",
  "email": "user@example.com"
}

Process:

  1. Auth Check: Verificerer admin bruger
  2. UnifiedUser Update:
    • consent_email = true
    • status = 'active'
    • last_activity_at = now
  3. EmailOptOut Reset:
    • Filter by email
    • Hvis exists: opted_out = false, opted_in_at = now
  4. UserEvent Log:
    • event_type: 'consent_updated'
    • metadata.action: 'reactivated_email_consent'
    • metadata.performed_by: admin.email

Output:

{
  "success": true,
  "message": "Email genaktiveret",
  "email": "user@example.com"
}

Security:

  • Kræver admin auth (403 Forbidden hvis ikke)
  • Logger hvem der genaktiverede (accountability)
  • Opdaterer kun specifikke felter (ingen bulk operations)

3. sendEmailFromQueue (Opt-Out Check)

Path: functions/sendEmailFromQueue.js
Formål: Queue processor der sender planlagte emails

KRITISK Opt-Out Check:

Før email sendes, checker funktionen 3 opt-out sources i rækkefølge:

// 1. Check UnifiedUser master database
const unifiedUsers = await base44.asServiceRole.entities
  .UnifiedUser.filter({ email: contactEmail.toLowerCase().trim() });

if (unifiedUsers.length > 0) {
  const unifiedUser = unifiedUsers[0];
  if (unifiedUser.status === 'unsubscribed' || 
      unifiedUser.consent_email === false) {
    
    // CANCEL SENDING
    await base44.asServiceRole.entities.EmailSendQueue
      .update(item.id, { status: 'canceled' });
    
    console.log(`[BLOCKED] ${contactEmail} - unsubscribed in master DB`);
    continue; // Skip til næste email
  }
}

// 2. Check EmailOptOut records
const optOuts = await base44.asServiceRole.entities
  .EmailOptOut.filter({ email: contactEmail.toLowerCase().trim() });

if (optOuts.length > 0 && optOuts[0].opted_out === true) {
  await base44.asServiceRole.entities.EmailSendQueue
    .update(item.id, { status: 'canceled' });
  
  console.log(`[BLOCKED] ${contactEmail} - opted out`);
  continue;
}

// 3. Check EmailContact status (hvis lead type)
if (emailContact && 
    (emailContact.unsubscribed_at || 
     emailContact.status !== 'active')) {
  
  await base44.asServiceRole.entities.EmailSendQueue
    .update(item.id, { status: 'canceled' });
  continue;
}

// Hvis alle checks passed → send email

Design Rationale:

  • Triple redundancy: Maksimal sikkerhed mod at sende til opted-out users
  • Master DB priority: UnifiedUser er source of truth
  • Cancel ikke fail: Queue item markeres 'canceled', ikke 'failed'
  • Logging: Detaljerede console logs for debugging

🌐 Frontend Integration

1. EmailAfmeldConfirm Page

Path: pages/EmailAfmeldConfirm.js
Route: /EmailAfmeldConfirm?email=user@example.com

State Machine:

confirm → loading → success/error
   ↓         ↓          ↓
  UI1      UI2        UI3

States:

A) CONFIRM (Initial)

  • Viser email fra URL param
  • "Ja, afmeld mig" knap
  • "Nej, gå tilbage" link

B) LOADING

  • Spinner animation
  • "Behandler afmelding..." tekst

C) SUCCESS

  • Grøn check ikon
  • "Du er nu afmeldt" besked
  • Viser email confirmation

D) ERROR

  • Rød X ikon
  • Error message
  • Kontakt info

Code Flow:

const handleOptOut = async () => {
  setStatus("loading");
  
  try {
    const response = await base44.functions.invoke(
      'handleEmailUnsubscribe', 
      { email: email }
    );
    
    if (response.data.success) {
      setStatus("success");
    } else {
      setStatus("error");
      setError(response.data.error);
    }
  } catch (err) {
    setStatus("error");
    setError(err.message);
  }
};

2. Email Template Links

Embedded i alle email templates:

<!-- Standard afmeld link -->
<a href="https://loanly24.dk/api/functions/handleEmailUnsubscribe?email={{email}}">
  Afmeld
</a>

<!-- Med List-Unsubscribe header (RFC 8058) -->
<meta name="List-Unsubscribe" 
      content="<https://loanly24.dk/api/functions/handleEmailUnsubscribe?email={{email}}>">
<meta name="List-Unsubscribe-Post" 
      content="List-Unsubscribe=One-Click">

Brevo Template Integration:

I sendEmailFromQueue.js:

const unsubscribeLink = 
  `https://loanly24.dk/api/functions/handleEmailUnsubscribe?email=${encodeURIComponent(contactEmail)}`;

const personalizedHtml = htmlContent
  .replace(/{{UNSUBSCRIBE_LINK}}/g, unsubscribeLink);

await sendViaBrevo({
  ...
  htmlContent: personalizedHtml,
  headers: {
    'List-Unsubscribe': `<${unsubscribeLink}>`,
    'List-Unsubscribe-Post': 'List-Unsubscribe=One-Click'
  }
});

🔗 Brevo Webhook Integration

Path: functions/handleBrevoWebhook.js
Formål: Modtager events fra Brevo email provider

Supported Events:

  • open - Email åbnet
  • click - Link klikket
  • hard_bounce - Permanent bounce
  • soft_bounce - Midlertidig bounce
  • unsubscribe - Bruger afmeldte via Brevo's native link
  • complaint - Spam klage

Unsubscribe Handling:

if (eventType === 'unsubscribe') {
  // Find enrollment
  const enrollment = await base44.asServiceRole.entities
    .EmailEnrollment.filter({
      campaign_id: job.campaign_id,
      contact_id: job.contact_id
    }).then(e => e[0]);

  if (enrollment) {
    // Mark enrollment as unsubscribed
    await base44.asServiceRole.entities.EmailEnrollment
      .update(enrollment.id, {
        status: 'unsubscribed'
      });
  }
  
  // TODO: Også opdater EmailOptOut + UnifiedUser
  // (skal implementeres for fuld sync)
}

Design Note:

  • Webhook returnerer ALTID 200 OK (ellers retry loop)
  • Async processing uden at blokere response
  • Idempotent: Kan håndtere duplicate events

🛡️ Admin Tools - UsersDatabaseV2

Path: pages/UsersDatabaseV2.js
Formål: Admin dashboard for bruger-database

Genaktiverings-workflow:

  1. Admin finder bruger i tabel
  2. Hvis status === 'unsubscribed':
    • Viser "Email" knap med RotateCw ikon
  3. Klik trigger mutation:
const reactivateMutation = useMutation({
  mutationFn: async ({ userId, email }) => {
    const response = await base44.functions.invoke(
      'reactivateEmailConsent', 
      { userId, email }
    );
    return response.data;
  },
  onSuccess: () => {
    queryClient.invalidateQueries({ queryKey: ["unifiedUsers"] });
    toast.success("Email genaktiveret");
  }
});

const handleReactivate = (userId, email) => {
  if (confirm(`Genaktiver emails til ${email}?`)) {
    reactivateMutation.mutate({ userId, email });
  }
};

UI Display:

{u.status === "unsubscribed" && (
  <button
    onClick={() => handleReactivate(u.id, u.email)}
    disabled={reactivateMutation.isPending}
    className="px-2 py-1 bg-green-600 text-white rounded"
  >
    <RotateCw className="w-3 h-3" />
    Email
  </button>
)}

🔍 Testing & Debugging

Test Scenarie 1: Normal Afmelding

Setup:

  1. Send test email til test@example.com
  2. Klik afmeld link i email

Forventet:

  • Redirect til EmailAfmeldConfirm
  • Confirm screen vises
  • Efter confirm → Success screen
  • Database checks:
    EmailOptOut: opted_out=true, opted_out_at=<timestamp>
    EmailOptOutLog: action='opt_out', source='link'
    UnifiedUser: consent_email=false, status='unsubscribed'
    

Logs:

[handleEmailUnsubscribe] Processing opt-out for test@example.com
[handleEmailUnsubscribe] Created EmailOptOut record
[handleEmailUnsubscribe] Updated UnifiedUser
[handleEmailUnsubscribe] Success

Test Scenarie 2: Genaktivering

Setup:

  1. Afmeld bruger (Scenarie 1)
  2. Log ind som admin
  3. Gå til UsersDatabaseV2
  4. Find bruger → klik "Email" knap

Forventet:

  • Confirm dialog vises
  • Success toast efter bekræftelse
  • Database checks:
    EmailOptOut: opted_out=false, opted_in_at=<timestamp>
    UnifiedUser: consent_email=true, status='active'
    UserEvent: event_type='consent_updated', 
               metadata.action='reactivated_email_consent'
    

Test Scenarie 3: Queue Blokkering

Setup:

  1. Afmeld bruger
  2. Planlæg email til brugeren (via campaign)
  3. Run sendEmailFromQueue

Forventet:

  • Email sendes IKKE
  • Queue item status → 'canceled'
  • Console log:
    [UNSUBSCRIBE CHECK] Email test@example.com is unsubscribed - CANCELED
    

Database check:

EmailSendQueue: status='canceled'
EmailEvent: event_type='unsubscribed' (hvis logged)

📊 Monitoring & Analytics

Key Metrics

Dashboard Query:

// Total opted out users
const optedOutCount = await base44.entities.EmailOptOut
  .filter({ opted_out: true }).length;

// Opt-outs last 7 days
const recentOptOuts = await base44.entities.EmailOptOutLog
  .filter({ 
    action: 'opt_out',
    created_date: { $gte: sevenDaysAgo }
  }).length;

// Opt-out rate per campaign
const campaign = await base44.entities.CampaignBroadcast.get(campaignId);
const optOutRate = (campaign.unsubscribe_count / campaign.sent_count) * 100;

Health Checks

Weekly Admin Review:

  1. Check EmailOptOutLog for anomalies
  2. Verify EmailOptOut.opted_out matches UnifiedUser.consent_email
  3. Monitor opt-out rate (alarm hvis >2% per campaign)

Audit Log Query:

// Find alle opt-out actions sidste måned
const logs = await base44.entities.EmailOptOutLog.filter({
  created_date: { $gte: lastMonth },
  action: 'opt_out'
}, '-created_date', 1000);

⚠️ Common Issues & Solutions

Issue 1: Email sendt til opted-out bruger

Symptom: Bruger rapporterer email modtaget efter afmelding

Debug:

  1. Check EmailOptOut record:

    const optOut = await base44.entities.EmailOptOut
      .filter({ email: 'user@example.com' });
    console.log(optOut);
    
  2. Check EmailSendQueue status:

    const queueItem = await base44.entities.EmailSendQueue
      .filter({ contact_id: contactId, status: 'sent' });
    

Root Causes:

  • Email normalisering fejl (case sensitivity)
  • Race condition: Opt-out under queue processing
  • Queue item created før opt-out

Solution:

  • Tilføj double-check i queue processor LIGE før send
  • Normalisér email konsistent alle steder

Issue 2: Opt-out link virker ikke

Symptom: Link fører til 404 eller error

Debug:

  1. Check URL format:

    Korrekt: /api/functions/handleEmailUnsubscribe?email=test@example.com
    Forkert: /EmailAfmeldConfirm?email=... (gammel format)
    
  2. Test direkte POST:

    curl -X POST https://loanly24.dk/api/functions/handleEmailUnsubscribe \
      -H "Content-Type: application/json" \
      -d '{"email":"test@example.com"}'
    

Solution:

  • Opdater alle email templates til korrekt URL
  • Tilføj redirect fra gammel URL til ny

Issue 3: Genaktivering fejler

Symptom: Admin får error ved genaktivering

Debug:

  1. Check admin auth:

    const user = await base44.auth.me();
    console.log(user.role); // Skal være 'admin'
    
  2. Check userId eksisterer:

    const user = await base44.entities.UnifiedUser.get(userId);
    

Solution:

  • Verify user.role === 'admin' i frontend før knap vises
  • Tilføj better error messages i backend

🔒 GDPR Compliance

Data Subject Rights

Ret til sletning (Right to Erasure):

Når bruger anmoder om sletning:

  1. IKKE slet EmailOptOut record (juridisk grund: "legitimate interest")
  2. BEHOLD opt-out status permanent
  3. Slet persondata fra andre entities:
    • UnifiedUser: Slet navn, telefon, etc.
    • EmailContact: Anonymiser eller slet
    • Lead: Anonymiser eller slet

Implementation:

// GDPR deletion (anonymize men keep opt-out)
await base44.entities.UnifiedUser.update(userId, {
  first_name: '[DELETED]',
  last_name: '[DELETED]',
  phone: null,
  // BEHOLD: email, consent_email=false, status='unsubscribed'
});

// EmailOptOut forbliver uændret (prevent re-subscription)

Rationale:

  • Opt-out er juridisk forpligtelse (ikke "persondata" efter GDPR)
  • Forhindrer utilsigtet re-subscription af slettet bruger

Audit Trail Requirements

EmailOptOutLog opfylder GDPR Art. 30 (Records of processing):

  • Hvem udførte handlingen (performed_by)
  • Hvornår (created_date timestamp)
  • Hvor fra (ip_address, user_agent)
  • Hvilken handling (action: opt_out/opt_in)

Retention:

  • EmailOptOut: Permanent (eller indtil bruger slettes + 3 år)
  • EmailOptOutLog: Minimum 3 år efter sidste aktivitet

🚀 Future Enhancements

1. Preferences Center

Formål: Granular email preferences (ikke bare on/off)

Design:

// Ny entity: EmailPreferences
{
  email: "user@example.com",
  newsletters: true,      // Nyhedsbreve
  promotions: false,      // Kampagner
  transactional: true,    // Transaktions-emails (altid true)
  frequency: "weekly"     // daily, weekly, monthly
}

Frontend:

  • Ny side: /email-preferences?email=...
  • Checkboxes for hver kategori
  • "Gem præferencer" knap

2. Re-engagement Campaigns

Formål: Win-back campaigns for opted-out users (med eksplicit opt-in)

Workflow:

  1. Filter opted-out users >6 months ago
  2. Send SMS (IKKE email) med re-opt-in link
  3. Link → Preferences center
  4. Bruger vælger præferencer → opted back in

3. Brevo Sync Enhancement

Problem: Brevo webhook håndterer ikke fuldt opt-out flow

Solution: Tilføj til handleBrevoWebhook.js:

if (eventType === 'unsubscribe') {
  // Call internal opt-out function
  await fetch('https://loanly24.dk/api/functions/handleEmailUnsubscribe', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ 
      email: event.email,
      source: 'brevo_webhook'
    })
  });
}

📝 Checklist - Deployment

Før deploy af ændringer til opt-out systemet:

  • [ ] Test alle 3 test scenarier (se Testing sektion)
  • [ ] Verify database writes til alle 6 entities
  • [ ] Check EmailOptOut normalisering (lowercase+trim)
  • [ ] Verify sendEmailFromQueue blokkerer opted-out emails
  • [ ] Test admin genaktivering i UsersDatabaseV2
  • [ ] Review EmailOptOutLog for compliance
  • [ ] Backup production EmailOptOut tabel
  • [ ] Update email templates med korrekte links
  • [ ] Test Brevo webhook unsubscribe event
  • [ ] Document any schema changes i denne guide

🔗 Quick Reference

Entities:

  • EmailOptOut - Opt-out status
  • EmailOptOutLog - Audit trail
  • UnifiedUser - Master DB
  • EmailContact - Marketing contacts
  • UserEvent - Event log

Functions:

  • handleEmailUnsubscribe - POST endpoint for opt-out
  • reactivateEmailConsent - Admin genaktivering
  • sendEmailFromQueue - Queue processor med opt-out check
  • handleBrevoWebhook - Brevo events

Pages:

  • EmailAfmeldConfirm - User-facing opt-out page
  • UsersDatabaseV2 - Admin dashboard

URLs:

  • Opt-out: /api/functions/handleEmailUnsubscribe?email=...
  • Confirm: /EmailAfmeldConfirm?email=...
  • Webhook: /api/functions/handleBrevoWebhook

END OF DOCUMENTATION

Loanly24

Vi sammenligner lån for at hjælpe dig med at træffe et informeret valg. Tjenesten er gratis og uforpligtende.

Kontakt

Nexa Finance A/S

Vesterbrogade 149

1620 København V

CVR: DK37979307

info@loanly24.dk

Loanly24.dk er en uafhængig sammenligningsservice for finansielle produkter. Vi tilbyder ikke egne lån eller kredit, men formidler forespørgsler videre til vores samarbejdspartnere, som er registrerede finansielle virksomheder under tilsyn af Finanstilsynet. Loanly24.dk kan modtage kommission for henvisning til låneudbydere, hvilket kan have indflydelse på sorteringsrækkefølgen. Oversigten er ikke udtømmende for samtlige lånemuligheder på markedet. Vi garanterer ikke godkendelse af lån, og alle vilkår og renter fastsættes af den enkelte långiver. Informationen på siden kan indeholde fejl eller ufuldstændige oplysninger. Opdaterede vilkår finder du altid hos långiver.

© 2026 Loanly24. Alle rettigheder forbeholdes.|Privatlivspolitik|Cookies