diff --git a/gajim/common/app.py b/gajim/common/app.py
index 9ec68329be6f06ad5937f381081a02c3e68a845f..e41d5c5565a5a26009e7d602a31eae4dc7607739 100644
--- a/gajim/common/app.py
+++ b/gajim/common/app.py
@@ -140,7 +140,6 @@
     'AV': False,
     'GEOCLUE': False,
     'UPNP': False,
-    'PYCURL': False,
     'GSOUND': False,
     'GSPELL': False,
     'IDLE': False,
@@ -239,13 +238,6 @@ def detect_dependencies():
     except ValueError:
         pass
 
-    # PYCURL
-    try:
-        import pycurl  # pylint: disable=unused-import
-        _dependencies['PYCURL'] = True
-    except ImportError:
-        pass
-
     # IDLE
     try:
         from gajim.common import idle
diff --git a/gajim/common/helpers.py b/gajim/common/helpers.py
index 451680b99603443886d469a08f10ad4af6d98482..c2aa9fba5bc90bfdd98241b95d038240d5585432 100644
--- a/gajim/common/helpers.py
+++ b/gajim/common/helpers.py
@@ -38,7 +38,6 @@
 import hashlib
 import shlex
 import socket
-import time
 import logging
 import json
 import copy
@@ -52,7 +51,6 @@
 from string import Template
 import urllib
 from urllib.parse import unquote
-from io import StringIO
 from encodings.punycode import punycode_encode
 from functools import wraps
 from packaging.version import Version as V
@@ -84,9 +82,6 @@
 from gajim.common.const import SHOW_LIST
 from gajim.common.structs import URI
 
-if app.is_installed('PYCURL'):
-    import pycurl
-
 
 log = logging.getLogger('gajim.c.helpers')
 
@@ -871,137 +866,6 @@ def get_proxy(proxy_name):
                      username=username,
                      password=password)
 
-def get_proxy_info(account):
-    p = app.config.get_per('accounts', account, 'proxy')
-    if not p:
-        p = app.config.get('global_proxy')
-    if p and p in app.config.get_per('proxies'):
-        proxy = {}
-        proxyptr = app.config.get_per('proxies', p)
-        if not proxyptr:
-            return proxy
-        for key in proxyptr.keys():
-            proxy[key] = proxyptr[key]
-        return proxy
-
-def _get_img_direct(attrs):
-    """
-    Download an image. This function should be launched in a separated thread.
-    """
-    mem = b''
-    alt = ''
-    max_size = 2*1024*1024
-    if 'max_size' in attrs:
-        max_size = attrs['max_size']
-    # Wait maximum 10s for connection
-    socket.setdefaulttimeout(10)
-    try:
-        req = urllib.request.Request(attrs['src'])
-        req.add_header('User-Agent', 'Gajim ' + app.version)
-        f = urllib.request.urlopen(req)
-    except Exception as ex:
-        log.debug('Error loading image %s ', attrs['src']  + str(ex))
-        alt = attrs.get('alt', 'Broken image')
-    else:
-        # Wait 2s between each byte
-        try:
-            f.fp._sock.fp._sock.settimeout(2)
-        except Exception:
-            pass
-
-        # On a slow internet connection with ~1000kbps
-        # you need ~10 seconds for 1 MB
-        deadline = time.time() + (10 * (max_size / 1048576))
-        while True:
-            if time.time() > deadline:
-                log.debug('Timeout loading image %s ', attrs['src'])
-                mem = ''
-                alt = attrs.get('alt', '')
-                if alt:
-                    alt += '\n'
-                alt += _('Timeout loading image')
-                break
-            try:
-                temp = f.read(100)
-            except socket.timeout as ex:
-                log.debug('Timeout loading image %s ', attrs['src'] + str(ex))
-                alt = attrs.get('alt', '')
-                if alt:
-                    alt += '\n'
-                alt += _('Timeout loading image')
-                break
-            if temp:
-                mem += temp
-            else:
-                break
-            if len(mem) > max_size:
-                alt = attrs.get('alt', '')
-                if alt:
-                    alt += '\n'
-                alt += _('Image is too big')
-                break
-        f.close()
-    return (mem, alt)
-
-def _get_img_proxy(attrs, proxy):
-    """
-    Download an image through a proxy. This function should be launched in a
-    separated thread.
-    """
-    if not app.is_installed('PYCURL'):
-        return '', _('PyCURL is not installed')
-    alt, max_size = '', 2*1024*1024
-    if 'max_size' in attrs:
-        max_size = attrs['max_size']
-    try:
-        b = StringIO()
-        c = pycurl.Curl()
-        c.setopt(pycurl.URL, attrs['src'].encode('utf-8'))
-        c.setopt(pycurl.FOLLOWLOCATION, 1)
-        # Wait maximum 10s for connection
-        c.setopt(pycurl.CONNECTTIMEOUT, 10)
-
-        # On a slow internet connection with ~1000kbps
-        # you need ~10 seconds for 1 MB
-        c.setopt(pycurl.TIMEOUT, 10 * (max_size / 1048576))
-        c.setopt(pycurl.MAXFILESIZE, max_size)
-        c.setopt(pycurl.WRITEFUNCTION, b.write)
-        c.setopt(pycurl.USERAGENT, 'Gajim ' + app.version)
-        # set proxy
-        c.setopt(pycurl.PROXY, proxy['host'].encode('utf-8'))
-        c.setopt(pycurl.PROXYPORT, proxy['port'])
-        if proxy['useauth']:
-            c.setopt(pycurl.PROXYUSERPWD, proxy['user'].encode('utf-8')\
-                + ':' + proxy['pass'].encode('utf-8'))
-            c.setopt(pycurl.PROXYAUTH, pycurl.HTTPAUTH_ANY)
-        if proxy['type'] == 'http':
-            c.setopt(pycurl.PROXYTYPE, pycurl.PROXYTYPE_HTTP)
-        elif proxy['type'] == 'socks5':
-            c.setopt(pycurl.PROXYTYPE, pycurl.PROXYTYPE_SOCKS5)
-        c.close()
-        t = b.getvalue()
-        return (t, attrs.get('alt', ''))
-    except pycurl.error as ex:
-        alt = attrs.get('alt', '')
-        if alt:
-            alt += '\n'
-        if ex.errno == pycurl.E_FILESIZE_EXCEEDED:
-            alt += _('Image is too big')
-        elif ex.errno == pycurl.E_OPERATION_TIMEOUTED:
-            alt += _('Timeout loading image')
-        else:
-            alt += _('Error loading image')
-    except Exception as ex:
-        log.debug('Error loading image %s ', attrs['src']  + str(ex))
-        alt = attrs.get('alt', 'Broken image')
-    return ('', alt)
-
-def download_image(account, attrs):
-    proxy = get_proxy_info(account)
-    if proxy and proxy['type'] in ('http', 'socks5'):
-        return _get_img_proxy(attrs, proxy)
-    return _get_img_direct(attrs)
-
 def version_condition(current_version, required_version):
     if V(current_version) < V(required_version):
         return False
diff --git a/gajim/gtk/htmltextview.py b/gajim/gtk/htmltextview.py
index 37c41176f227875c5eec8475c441def92817b5d2..f6e18053f5d294a6161775a39800e9030c582556 100644
--- a/gajim/gtk/htmltextview.py
+++ b/gajim/gtk/htmltextview.py
@@ -33,7 +33,6 @@
 
 import re
 import logging
-import urllib
 import xml.sax
 import xml.sax.handler
 from io import StringIO
@@ -42,16 +41,12 @@
 from gi.repository import Pango
 from gi.repository import Gtk
 from gi.repository import Gdk
-from gi.repository import GdkPixbuf
 from gi.repository import GLib
 
 from gajim.common import app
-from gajim.common import helpers
-from gajim.common.i18n import _
 from gajim.common.const import StyleAttr
 from gajim.common.helpers import open_uri
 from gajim.common.helpers import parse_uri
-from gajim.gtk.util import load_icon
 from gajim.gtk.util import get_cursor
 
 from gajim.gui_menu_builder import get_conv_context_menu
@@ -510,123 +505,6 @@ def _create_url(self, href, title, type_, id_):
             tag.title = title
         return tag
 
-    def _update_img(self, output, attrs, img_mark, tags):
-        '''Callback function called after the function helpers.download_image.
-        '''
-        mem, alt = output
-        self._process_img(attrs, (mem, alt, img_mark, tags))
-
-    def _process_img(self, attrs, loaded=None):
-        '''Process a img tag.
-        '''
-        mem = ''
-        pixbuf = None
-        replace_mark = None
-        replace_tags = None
-
-        try:
-            if attrs['src'].startswith('data:image/'):
-                # The "data" URL scheme http://tools.ietf.org/html/rfc2397
-                import base64
-                img = attrs['src'].split(',')[1]
-                mem = base64.standard_b64decode(urllib.parse.unquote(
-                    img).encode('utf-8'))
-            elif loaded is not None:
-                (mem, alt, replace_mark, replace_tags) = loaded
-            else:
-                if self.conv_textview:
-                    img_mark = self.textbuf.create_mark(None, self.iter, True)
-                    app.thread_interface(
-                        helpers.download_image,
-                        [self.conv_textview.account, attrs],
-                        self._update_img,
-                        [attrs, img_mark, self._get_style_tags()])
-                    alt = attrs.get('alt', '')
-                    if alt:
-                        alt += '\n'
-                    alt += _('Loading')
-                    pixbuf = load_icon('image-missing',
-                                       self.textview,
-                                       pixbuf=True)
-            if mem:
-                # Caveat: GdkPixbuf is known not to be safe to load
-                # images from network... this program is now potentially
-                # hackable ;)
-                loader = GdkPixbuf.PixbufLoader()
-                dims = [0, 0]
-                def height_cb(length):
-                    dims[1] = length
-                def width_cb(length):
-                    dims[0] = length
-                # process width and height attributes
-                width = attrs.get('width')
-                height = attrs.get('height')
-                # override with width and height styles
-                for attr, val in style_iter(attrs.get('style', '')):
-                    if attr == 'width':
-                        width = val
-                    elif attr == 'height':
-                        height = val
-                if width:
-                    self._parse_length(width, False, False, 1, 1000, width_cb)
-                if height:
-                    self._parse_length(height, False, False, 1, 1000, height_cb)
-
-                def set_size(_pixbuf, width_, height_, dims):
-                    """
-                    FIXME: Floats should be relative to the whole textview, and
-                    resize with it. This needs new pifbufs for every resize,
-                    GdkPixbuf.Pixbuf.scale_simple or similar.
-                    """
-                    if isinstance(dims[0], float):
-                        dims[0] = int(dims[0] * width_)
-                    elif not dims[0]:
-                        dims[0] = width_
-                    if isinstance(dims[1], float):
-                        dims[1] = int(dims[1] * height_)
-                    if not dims[1]:
-                        dims[1] = height_
-                    loader.set_size(*dims)
-
-                if width or height:
-                    loader.connect('size-prepared', set_size, dims)
-                loader.write(mem)
-                loader.close()
-                pixbuf = loader.get_pixbuf()
-                alt = attrs.get('alt', '')
-            working_iter = self.iter
-            if replace_mark is not None:
-                working_iter = self.textbuf.get_iter_at_mark(replace_mark)
-                next_iter = working_iter.copy()
-                next_iter.forward_char()
-                self.textbuf.delete(working_iter, next_iter)
-                self.textbuf.delete_mark(replace_mark)
-            if pixbuf is not None:
-                if replace_mark:
-                    tags = replace_tags
-                else:
-                    tags = self._get_style_tags()
-                if tags:
-                    tmpmark = self.textbuf.create_mark(None, working_iter, True)
-                self.textbuf.insert_pixbuf(working_iter, pixbuf)
-                self.starting = False
-                if tags:
-                    start = self.textbuf.get_iter_at_mark(tmpmark)
-                    for tag in tags:
-                        self.textbuf.apply_tag(tag, start, working_iter)
-                    self.textbuf.delete_mark(tmpmark)
-            else:
-                self._insert_text('[IMG: %s]' % alt, working_iter)
-        except Exception as ex:
-            log.error('Error loading image %s', str(ex))
-            pixbuf = None
-            alt = attrs.get('alt', 'Broken image')
-            try:
-                loader.close()
-            except Exception:
-                pass
-        return pixbuf
-
     def _begin_span(self, style, tag=None, id_=None):
         if style is None:
             self.styles.append(tag)
@@ -730,8 +608,7 @@ def startElement(self, name, attrs):
                 tag.is_anchor = True
         elif name in LIST_ELEMS:
             style += ';margin-left: 2em'
-        elif name == 'img':
-            tag = self._process_img(attrs)
+
         if name in _element_styles:
             style += _element_styles[name]
         # so that explicit styles override implicit ones,
diff --git a/mypy.ini b/mypy.ini
index a5b726f6257ceec0c276ff8ea185a3dc55642043..bfa75b4a242f2fd851c06fc2e58da61c5acbf65f 100644
--- a/mypy.ini
+++ b/mypy.ini
@@ -40,9 +40,6 @@ ignore_missing_imports = True
 [mypy-PIL.*]
 ignore_missing_imports = True
 
-[mypy-pycurl.*]
-ignore_missing_imports = True
-
 [mypy-netifaces.*]
 ignore_missing_imports = True
 
diff --git a/pylintrc b/pylintrc
index 274dcf926be6dea847c2bd431a7a2e331dc1a22d..3cd5791e453ae496e7d3152747f78c5355113dbc 100644
--- a/pylintrc
+++ b/pylintrc
@@ -3,7 +3,7 @@
 # A comma-separated list of package or module names from where C extensions may
 # be loaded. Extensions are loading into the active Python interpreter and may
 # run arbitrary code
-extension-pkg-whitelist=pycurl
+extension-pkg-whitelist=
 
 # Add files or directories to the blacklist. They should be base names, not
 # paths.