Son güncelleme: Nisan 2026 · AnomixLabs Teknik Ekibi
İletişim formu bir sitenin müşteriye açılan kapısıdır. Spam'e açık, hatalı veya yavaş bir form doğrudan gelir kaybıdır. Doğru yapılmış bir form ise güven verir.
1. ContactForm Modeli ve ModelForm
from django.db import models
class ContactMessage(models.Model):
name = models.CharField('Ad Soyad', max_length=100)
email = models.EmailField('E-Posta')
subject = models.CharField('Konu', max_length=200)
message = models.TextField('Mesaj')
attachment = models.FileField(
'Dosya Eki', upload_to='contact/', blank=True, null=True
)
ip_address = models.GenericIPAddressField(blank=True, null=True)
is_read = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name = 'İletişim Mesajı'
ordering = ['-created_at']
from django import forms
from .models import ContactMessage
ALLOWED_EXTENSIONS = ['pdf', 'doc', 'docx', 'jpg', 'png', 'zip']
MAX_FILE_SIZE = 5 * 1024 * 1024 # 5 MB
class ContactForm(forms.ModelForm):
honeypot = forms.CharField(required=False, widget=forms.HiddenInput)
class Meta:
model = ContactMessage
fields = ['name', 'email', 'subject', 'message', 'attachment']
def clean_honeypot(self):
if self.cleaned_data.get('honeypot'):
raise forms.ValidationError('Bot tespiti')
return ''
def clean_attachment(self):
f = self.cleaned_data.get('attachment')
if not f:
return f
ext = f.name.rsplit('.', 1)[-1].lower()
if ext not in ALLOWED_EXTENSIONS:
raise forms.ValidationError(f'İzin verilmeyen format. Kabul edilenler: {ALLOWED_EXTENSIONS}')
if f.size > MAX_FILE_SIZE:
raise forms.ValidationError('Dosya 5 MB sınırını aşıyor.')
return f
2. FormView ile Güvenli POST İşlemi
from django.views.generic.edit import FormView
from django.core.mail import EmailMessage
from django.contrib import messages
from django.conf import settings
from .forms import ContactForm
class ContactView(FormView):
template_name = 'contact.html'
form_class = ContactForm
success_url = '/iletisim/tesekkurler/'
def form_valid(self, form):
msg = form.save(commit=False)
msg.ip_address = self.request.META.get('REMOTE_ADDR')
msg.save()
self._send_email(msg)
messages.success(self.request, 'Mesajınız başarıyla gönderildi!')
return super().form_valid(form)
def _send_email(self, msg):
email = EmailMessage(
subject=f'[İletişim] {msg.subject}',
body=(
f'Gönderen: {msg.name} \n'
f'Mesaj:\n{msg.message}'
),
from_email=settings.DEFAULT_FROM_EMAIL,
to=[settings.CONTACT_EMAIL],
reply_to=[msg.email],
)
if msg.attachment:
email.attach_file(msg.attachment.path)
email.send(fail_silently=False)
3. HTML Şablonu ve Form Render
İletişim formunun template'de görünmesi için iki yaklaşım var. Önerileni: django-crispy-forms ile otomatik stillendirilmiş çıktı:

$ pip install crispy-tailwind # Tailwind için
# veya: pip install crispy-bootstrap5
INSTALLED_APPS += ['crispy_forms', 'crispy_tailwind']
CRISPY_ALLOWED_TEMPLATE_PACKS = 'tailwind'
CRISPY_TEMPLATE_PACK = 'tailwind'
{% load crispy_forms_tags %}
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
<button type="submit">Gönder</button>
</form>
{# Başarı/hata mesajları #}
{% for message in messages %}
<div class="alert-{{ message.tags }}">{{ message }}</div>
{% endfor %}
Crispy-forms kullanmak istemiyorsanız Django'nun yerleşik render yöntemi:
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Gönder</button>
</form>
Önemli: Dosya eki alanı içeren formlarda enctype="multipart/form-data" zorunludur — aksi takdirde yüklenen dosya POST gövdesinde yer almaz ve request.FILES boş gelir.
4. Gmail SMTP Yapılandırması
Gmail hesabınızda 2FA etkin olmalıdır. 'Uygulama Şifresi' oluşturun (myaccount.google.com → Güvenlik → Uygulama Şifreleri). Normal hesap şifrenizi kullanmayın:

EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
EMAIL_USE_TLS=True
EMAIL_HOST_USER=sirket@gmail.com
EMAIL_HOST_PASSWORD=xxxx-xxxx-xxxx-xxxx # Uygulama şifresi
DEFAULT_FROM_EMAIL=AnomixLabs
CONTACT_EMAIL=info@anomixlabs.com
EMAIL_HOST = env('EMAIL_HOST')
EMAIL_PORT = env.int('EMAIL_PORT', 587)
EMAIL_USE_TLS = env.bool('EMAIL_USE_TLS', True)
EMAIL_HOST_USER = env('EMAIL_HOST_USER')
EMAIL_HOST_PASSWORD = env('EMAIL_HOST_PASSWORD')
DEFAULT_FROM_EMAIL = env('DEFAULT_FROM_EMAIL')
CONTACT_EMAIL = env('CONTACT_EMAIL')
5. reCAPTCHA v3 Entegrasyonu
reCAPTCHA v3 görünmez çalışır — kullanıcıdan 'ben robot değilim' tıklaması istemez. Google 0.0-1.0 arası bir güven skoru döndürür, 0.5 üzeri normal kullanıcı kabul edilir:
$ pip install django-recaptcha
INSTALLED_APPS += ['django_recaptcha']
RECAPTCHA_PUBLIC_KEY = env('RECAPTCHA_PUBLIC_KEY')
RECAPTCHA_PRIVATE_KEY = env('RECAPTCHA_PRIVATE_KEY')
# v3 için minimum skor (0.0 - 1.0)
RECAPTCHA_REQUIRED_SCORE = 0.5
from django_recaptcha.fields import ReCaptchaField
from django_recaptcha.widgets import ReCaptchaV3
class ContactForm(forms.ModelForm):
captcha = ReCaptchaField(widget=ReCaptchaV3)
# ...
6. Honeypot Spam Koruması
CSS ile gizlenmiş bir alan — botlar tüm alanları doldurur, gerçek kullanıcılar görmez. reCAPTCHA API'sine ihtiyaç duymadan ek koruma katmanı sağlar:
class ContactForm(forms.ModelForm):
# Botların göreceği ama kullanıcıların görmeyeceği alan
website = forms.CharField(required=False, widget=forms.HiddenInput)
def clean_website(self):
if self.cleaned_data.get('website'):
# Bot bu alanı doldurdu — form geçersiz
raise forms.ValidationError('Spam tespit edildi')
return ''
7. Rate Limiting ile Kötüye Kullanım Önleme
from django.core.cache import cache
class ContactView(FormView):
def form_valid(self, form):
ip = self.request.META.get('REMOTE_ADDR', '')
cache_key = f'contact_rate_{ip}'
count = cache.get(cache_key, 0)
if count >= 3: # Saatte 3 mesaj limiti
messages.error(self.request, 'Çok fazla mesaj gönderdiniz. Lütfen bekleyin.')
return self.form_invalid(form)
cache.set(cache_key, count + 1, timeout=3600) # 1 saat
return super().form_valid(form)
8. Async Email: Celery ile (Opsiyonel)
Email gönderimi ağ isteği gerektirdiğinden yavaş olabilir. Büyük hacimli projeler için Celery ile arka planda gönderin:
from celery import shared_task
from django.core.mail import EmailMessage
@shared_task
def send_contact_email_task(subject, body, from_email, to_emails, reply_to):
email = EmailMessage(
subject=subject,
body=body,
from_email=from_email,
to=to_emails,
reply_to=[reply_to],
)
email.send()
# views.py'de çağırma
send_contact_email_task.delay(
subject=f'[İletişim] {msg.subject}',
body=msg.message,
from_email=settings.DEFAULT_FROM_EMAIL,
to_emails=[settings.CONTACT_EMAIL],
reply_to=msg.email,
)
9. SPF ve DKIM: Email Deliverability
Gönderdiğiniz emailler spam klasörüne düşüyorsa bu teknik DNS kayıtları eksik demektir:
- SPF: DNS'e TXT kaydı ekleyin:
v=spf1 include:_spf.google.com ~all— Gmail'in sizin adınıza email gönderebileceğini belirtir. - DKIM: Google Workspace veya SendGrid panelinden CNAME kayıtları alın ve DNS'e ekleyin. Emailin imzalı gönderildiğini kanıtlar.
- DMARC:
v=DMARC1; p=quarantine; rua=mailto:dmarc@domain.com— SPF/DKIM başarısız olursa ne yapılacağını belirtir.
10. Test Ortamı: Mailtrap veya django-mail-panel
# Geliştirme: emailler konsola yazdırılır, gönderilmez
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
# Veya Mailtrap (gerçek SMTP gibi davranır, ama gerçek email gönderilmez)
EMAIL_HOST = 'sandbox.smtp.mailtrap.io'
EMAIL_HOST_USER = env('MAILTRAP_USER')
EMAIL_HOST_PASSWORD = env('MAILTRAP_PASS')
EMAIL_PORT = 2525
Özet
Profesyonel Django iletişim formu: ModelForm (validasyon), FormView (GET/POST), EmailMessage (dosya ekiyle), Gmail App Password (SMTP), reCAPTCHA v3 + honeypot (spam koruma), rate limiting (kötüye kullanım önleme), SPF/DKIM (deliverability). Production'da test etmek için Mailtrap kullanın.
Sıkça Sorulan Sorular
Gmail limitleri production'da sorun çıkarır mı? expand_more
Dosya eki boyut sınırı nasıl ayarlanır? expand_more
Async email için Celery yerine ne kullanabilirim? expand_more
reCAPTCHA v2 mi v3 mü tercih edilmeli? expand_more
Email gönderimi başarısız olursa ne yapmalı? expand_more
İletişim formunu admin panelinde nasıl yönetirim? expand_more
GDPR uyumu için formda ne yapmalıyım? expand_more
Ali Kasımoğlu
Full-stack Geliştirici & AnomixLabs Kurucusu
Python ve Django ekosisteminde uzmanlaşmış bir yazılım geliştirici. Modern web mimarileri, yapay zeka entegrasyonları ve minimalist kullanıcı deneyimleri üzerine odaklanıyor. AnomixLabs çatısı altında, karmaşık problemleri yalın ve etkili dijital çözümlere dönüştürmeyi hedefliyor.